From 907fc58ee2673b5966c5097cc8c46e6c129d722a Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 1 Jun 2020 12:15:36 -0400 Subject: [PATCH 01/20] Use tools v5.2 (#903) * Use [tools v5.2](https://github.com/openmaptiles/openmaptiles-tools/releases/tag/v5.2.0) * Use `mbtiles-tools meta-generate` instead of the removed `generate-metadata` script. * Remove `show-metadata` make target - it was just added and is not needed. ## Relevant changes * Upgrade [osml10n PG extension](https://github.com/giggls/mapnik-german-l10n) to the faster v2.5.9 (significant performance improvements merged upstream by @nyurik) --- .env | 2 +- Makefile | 7 ++----- quickstart.sh | 5 ----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.env b/.env index 335fff6..2e1d799 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ # This file defines default environment variables for all images # Use 3-part patch version to ignore patch updates, e.g. 5.0.0 -TOOLS_VERSION=5.1 +TOOLS_VERSION=5.2 # Make sure these values are in sync with the ones in .env-postgres file PGDATABASE=openmaptiles diff --git a/Makefile b/Makefile index 1a37f0b..3a8c9c9 100644 --- a/Makefile +++ b/Makefile @@ -203,10 +203,6 @@ import-sql: all start-db-nowait $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-sql' | \ awk -v s=": WARNING:" '$$0~s{print; print "\n*** WARNING detected, aborting"; exit(1)} 1' -.PHONY: show-metadata -show-metadata: init-dirs - $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools mbtiles-tools meta-all ./data/tiles.mbtiles - .PHONY: generate-tiles ifneq ($(wildcard data/docker-compose-config.yml),) DC_CONFIG_TILES:=-f docker-compose.yml -f ./data/docker-compose-config.yml @@ -216,7 +212,8 @@ generate-tiles: all start-db echo "Generating tiles ..."; \ $(DOCKER_COMPOSE) $(DC_CONFIG_TILES) run $(DC_OPTS) generate-vectortiles @echo "Updating generated tile metadata ..." - $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools generate-metadata ./data/tiles.mbtiles + $(DOCKER_COMPOSE) $(DC_CONFIG_TILES) run $(DC_OPTS) openmaptiles-tools \ + mbtiles-tools meta-generate ./data/tiles.mbtiles ./openmaptiles.yaml --auto-minmax --show-ranges .PHONY: start-tileserver start-tileserver: init-dirs diff --git a/quickstart.sh b/quickstart.sh index d019ea6..56ca978 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -304,11 +304,6 @@ echo "-------------------------------------------------------------------------- echo "====> : Stop PostgreSQL service ( but we keep PostgreSQL data volume for debugging )" make stop-db -echo " " -echo "-------------------------------------------------------------------------------------" -echo "====> : Show generated metadata" -make show-metadata - echo " " echo "-------------------------------------------------------------------------------------" echo "====> : Inputs - Outputs md5sum for debugging " From 1a31b9212e4c32cff259000574f7923e005ec43c Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 1 Jun 2020 12:33:26 -0400 Subject: [PATCH 02/20] Minor fix import-borders file param (#905) just like import-osm, import-borders can accept PBF_FILE param --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3a8c9c9..b07b138 100644 --- a/Makefile +++ b/Makefile @@ -196,7 +196,7 @@ import-data: start-db .PHONY: import-borders import-borders: start-db-nowait - $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-borders' + $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-borders $(PBF_FILE)' .PHONY: import-sql import-sql: all start-db-nowait From 546f26e68a7e35a8b2727d577e24b65293775232 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 1 Jun 2020 12:46:34 -0400 Subject: [PATCH 03/20] MVT: use gzip and generate for v3.0 (#906) This only changes the generated `getmvt(...)` function used by mvt users. Beginning with tools 5.1, postgis docker images uses postgis v3.0, and includes gzip extension --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b07b138..f07cddf 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,9 @@ build/mapping.yaml: init-dirs build-sql: init-dirs $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c \ 'generate-sql openmaptiles.yaml --dir ./build/sql \ - && generate-sqltomvt openmaptiles.yaml --key --postgis-ver 2.4.8 --function --fname=getmvt >> "./build/sql/run_last.sql"' + && generate-sqltomvt openmaptiles.yaml \ + --key --gzip --postgis-ver 3.0.1 \ + --function --fname=getmvt >> "./build/sql/run_last.sql"' .PHONY: clean clean: From fca53ef0ee4b1a3e227ad931230d84607c5684b8 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 1 Jun 2020 12:54:30 -0400 Subject: [PATCH 04/20] Minor makefile/quickstart cleanup (#907) * Make a few spacing adjustments for ease-of-reading and consistency * fix bbbike naming and other source urls * remove unneeded `override` * added `list-bbbike` target --- Makefile | 52 ++++++++++++++++++++++++++++++++------------------- quickstart.sh | 7 +++---- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index f07cddf..9e3aeec 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,45 @@ +# +# First section - common variable initialization +# + # Ensure that errors don't hide inside pipes SHELL = /bin/bash .SHELLFLAGS = -o pipefail -c # Options to run with docker and docker-compose - ensure the container is destroyed on exit # Containers run as the current user rather than root (so that created files are not root-owned) -DC_OPTS?=--rm -u $(shell id -u):$(shell id -g) +DC_OPTS ?= --rm -u $(shell id -u):$(shell id -g) # If set to a non-empty value, will use postgis-preloaded instead of postgis docker image -USE_PRELOADED_IMAGE?= +USE_PRELOADED_IMAGE ?= # If set, this file will be imported in the import-osm target PBF_FILE?= # Local port to use with postserve -PPORT?=8090 +PPORT ?= 8090 export PPORT # Local port to use with tileserver -TPORT?=8080 +TPORT ?= 8080 export TPORT # Allow a custom docker-compose project name ifeq ($(strip $(DC_PROJECT)),) - override DC_PROJECT:=$(notdir $(shell pwd)) - DOCKER_COMPOSE:= docker-compose + DC_PROJECT := $(notdir $(shell pwd)) + DOCKER_COMPOSE := docker-compose else - DOCKER_COMPOSE:= docker-compose --project-name $(DC_PROJECT) + DOCKER_COMPOSE := docker-compose --project-name $(DC_PROJECT) endif # Make some operations quieter (e.g. inside the test script) ifeq ($(strip $(QUIET)),) - QUIET_FLAG:= + QUIET_FLAG := else - QUIET_FLAG:=--quiet + QUIET_FLAG := --quiet endif # Use `xargs --no-run-if-empty` flag, if supported -XARGS:=xargs $(shell xargs --no-run-if-empty /dev/null && echo --no-run-if-empty) +XARGS := xargs $(shell xargs --no-run-if-empty /dev/null && echo --no-run-if-empty) # If running in the test mode, compare files rather than copy them TEST_MODE?=no @@ -47,12 +51,17 @@ else GRAPH_PARAMS=./layers endif +# Set OpenMapTiles host +OMT_HOST := http://$(firstword $(subst :, ,$(subst tcp://,,$(DOCKER_HOST))) localhost) + + +# +# TARGETS +# + .PHONY: all all: init-dirs build/openmaptiles.tm2source/data.yml build/mapping.yaml build-sql -# Set OpenMapTiles host -OMT_HOST:=http://$(firstword $(subst :, ,$(subst tcp://,,$(DOCKER_HOST))) localhost) - .PHONY: help help: @echo "==============================================================================" @@ -69,9 +78,9 @@ help: @echo "Hints for developers:" @echo " make # build source code" @echo " make list-geofabrik # list actual geofabrik OSM extracts for download" - @echo " make download-geofabrik area=albania # download OSM data from geofabrik, and create config file" - @echo " make download-osmfr area=asia/qatar # download OSM data from openstreetmap.fr, and create config file" - @echo " make download-bbike area=Amsterdam # download OSM data from bbike.org, and create config file" + @echo " make download-geofabrik area=albania # download OSM data from geofabrik.de and create config file" + @echo " make download-osmfr area=asia/qatar # download OSM data from openstreetmap.fr and create config file" + @echo " make download-bbbike area=Amsterdam # download OSM data from bbbike.org and create config file" @echo " make psql # start PostgreSQL console" @echo " make psql-list-tables # list all PostgreSQL tables" @echo " make vacuum-db # PostgreSQL: VACUUM ANALYZE" @@ -119,7 +128,8 @@ clean: rm -rf build .PHONY: destroy-db -destroy-db: override DC_PROJECT:=$(shell echo $(DC_PROJECT) | tr A-Z a-z) +# TODO: Use https://stackoverflow.com/a/27852388/177275 +destroy-db: DC_PROJECT := $(shell echo $(DC_PROJECT) | tr A-Z a-z) destroy-db: $(DOCKER_COMPOSE) down -v --remove-orphans $(DOCKER_COMPOSE) rm -fv @@ -151,8 +161,12 @@ stop-db: list-geofabrik: init-dirs $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools download-osm list geofabrik -OSM_SERVERS:=geofabrik osmfr bbbike -ALL_DOWNLOADS:=$(addprefix download-,$(OSM_SERVERS)) +.PHONY: list-bbbike +list-bbbike: init-dirs + $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools download-osm list bbbike + +OSM_SERVERS := geofabrik osmfr bbbike +ALL_DOWNLOADS := $(addprefix download-,$(OSM_SERVERS)) OSM_SERVER=$(patsubst download-%,%,$@) .PHONY: $(ALL_DOWNLOADS) $(ALL_DOWNLOADS): init-dirs diff --git a/quickstart.sh b/quickstart.sh index 56ca978..dd44a25 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -71,7 +71,6 @@ MIN_COMPOSE_VER=1.7.1 MIN_DOCKER_VER=1.12.3 STARTTIME=$(date +%s) STARTDATE=$(date +"%Y-%m-%dT%H:%M%z") -githash=$( git rev-parse HEAD ) log_file=./quickstart.log rm -f $log_file @@ -121,7 +120,7 @@ echo " : This will be logged to the $log_file file (for debugging) and to t echo " : Area : $osm_area " echo " : Download Server : $osm_server " echo " : Preloaded Image : $USE_PRELOADED_IMAGE " -echo " : Git version : $githash " +echo " : Git version : $(git rev-parse HEAD) " echo " : Started : $STARTDATE " echo " : Your bash version: $BASH_VERSION" echo " : Your OS : $OSTYPE" @@ -309,8 +308,8 @@ echo "-------------------------------------------------------------------------- echo "====> : Inputs - Outputs md5sum for debugging " rm -f ./data/quickstart_checklist.chk { - find build -type f | sort | xargs md5sum ; - find data -type f | sort | xargs md5sum ; + find build -type f | sort | xargs md5sum + find data -type f | sort | xargs md5sum } >> ./data/quickstart_checklist.chk cat ./data/quickstart_checklist.chk From 1486b7e0cb7c593884c881268c2dcd00b862c986 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Wed, 3 Jun 2020 15:37:45 -0400 Subject: [PATCH 05/20] Rework download area support (#908) Closes #904 * Make all data-related targets like `download*`, `import-osm`, `import-borders`, and `generate-tiles` into `area`-aware -- making it possible for multiple data files to coexist inside the `./data` dir. * Add `make download area=... [url=...]` command to automatically download any kind of area by checking Geofabrik, BBBike, and OSM.fr, optionally from a custom URL. Supports `area=planet` too. * Do not re-download area with `make download-*` if it already exists. * Automatically rename `-latest.osm.pbf` into `.osm.pbf` * If `area=...` parameter is not given to `make`, see if there is exactly one `*.osm.pbf` file, and if so, use `*` as the `area`. * Configure many variables in the .env file, overriding the defaults in tools * If `.osm.pbf` exists, but `.dc-config.pbf` is missing, generate it using `download-osm make-dc` command. Also: * closes #614 * closes #647 * partially addresses #261 --- .env | 11 +++ .github/workflows/tests.yml | 2 +- Makefile | 163 +++++++++++++++++++++++++++++------- README.md | 8 +- docker-compose.yml | 12 ++- quickstart.sh | 73 +++++----------- 6 files changed, 184 insertions(+), 85 deletions(-) diff --git a/.env b/.env index 2e1d799..c415676 100644 --- a/.env +++ b/.env @@ -24,3 +24,14 @@ FILTER_MAPNIK_OUTPUT=1 # Some area data like openstreetmap.fr can contain invalid references # that must be cleaned up before using it for borders -- set it to true. BORDERS_CLEANUP=false + +# The current setup assumes this file is placed inside the data/ dir +MBTILES_FILE=tiles.mbtiles +# This is the current repl_config.json location, pre-configured in the tools Dockerfile +# Makefile and quickstart replace it with the dynamically generated one, but we keep it here in case some other method is used to run. +IMPOSM_CONFIG_FILE=/usr/src/app/config/repl_config.json + +# import-borders temp files - set them here to defaults, and override in the Makefile based on the area +BORDERS_CLEANUP_FILE=data/borders/cleanup.pbf +BORDERS_PBF_FILE=data/borders/filtered.pbf +BORDERS_CSV_FILE=data/borders/lines.csv diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c807573..abb258c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -173,7 +173,7 @@ jobs: create_db() { make clean make init-dirs - cp ../ci_cache/perf-test-areas-latest.osm.pbf data/perf-test-areas-latest.osm.pbf + cp ../ci_cache/perf-test-areas-latest.osm.pbf data/perf-test-areas.osm.pbf make destroy-db make all make start-db diff --git a/Makefile b/Makefile index 9e3aeec..2e044fc 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,6 @@ DC_OPTS ?= --rm -u $(shell id -u):$(shell id -g) # If set to a non-empty value, will use postgis-preloaded instead of postgis docker image USE_PRELOADED_IMAGE ?= -# If set, this file will be imported in the import-osm target -PBF_FILE?= - # Local port to use with postserve PPORT ?= 8090 export PPORT @@ -55,6 +52,87 @@ endif OMT_HOST := http://$(firstword $(subst :, ,$(subst tcp://,,$(DOCKER_HOST))) localhost) +# +# Determine area to work on +# If $(area) parameter is not set and data/*.osm.pbf finds only one file, use it as $(area). +# Otherwise all make targets requiring area param will show an error. +# Note: If there are no data files, and user calls make download area=... once, +# they will not need to use area= parameter after that because there will be just a single file. +# + +# historically we have been using $(area) rather than $(AREA), so make both work +area ?= $(AREA) +# Ensure the $(AREA) param is set, or try to automatically determine it based on available data files +ifeq ($(strip $(area)),) + # if $area is not set. set it to the name of the *.osm.pbf file, but only if there is only one + data_files := $(wildcard data/*.osm.pbf) + ifneq ($(word 2,$(data_files)),) + AREA_ERROR := The 'area' parameter (or env var) has not been set, and there are more than one data/*.osm.pbf files. Set area to one of these IDs, or a new one: $(patsubst data/%.osm.pbf,'%',$(data_files)) + else + ifeq ($(word 1,$(data_files)),) + AREA_ERROR := The 'area' parameter (or env var) has not been set, and there are no data/*.osm.pbf files + else + # Keep just the name of the data file, without the .osm.pbf extension + area := $(strip $(basename $(basename $(notdir $(data_files))))) + # Rename area-latest.osm.pbf to area.osm.pbf + # TODO: This if statement could be removed in a few months once everyone is using the file without the `-latest`? + ifneq ($(area),$(area:-latest=)) + $(shell mv "data/$(area).osm.pbf" "data/$(area:-latest=).osm.pbf") + area := $(area:-latest=) + $(warning ATTENTION: File data/$(area)-latest.osm.pbf was renamed to $(area).osm.pbf.) + AREA_INFO := Detected area=$(area) based on the found data/$(area)-latest.osm.pbf (renamed to $(area).osm.pbf). Use 'area' parameter (or env var) to override. + else + AREA_INFO := Detected area=$(area) based on the found data/ pbf file. Use 'area' parameter (or env var) to override. + endif + endif + endif +endif + +# If set, this file will be downloaded in download-osm and imported in the import-osm targets +PBF_FILE ?= data/$(area).osm.pbf + +# For download-osm, allow URL parameter to download file from a given URL. Area param must still be provided. +ifneq ($(strip $(url)),) + DOWNLOAD_AREA := $(url) +else + DOWNLOAD_AREA := $(area) +endif + +# import-borders uses these temp files during border parsing/import +export BORDERS_CLEANUP_FILE ?= data/borders/$(area).cleanup.pbf +export BORDERS_PBF_FILE ?= data/borders/$(area).filtered.pbf +export BORDERS_CSV_FILE ?= data/borders/$(area).lines.csv + +# The file is placed into the $EXPORT_DIR=/export (mapped to ./data) +export MBTILES_FILE ?= $(area).mbtiles +MBTILES_LOCAL_FILE = data/$(MBTILES_FILE) + +# Location of the dynamically-generated imposm config file +export IMPOSM_CONFIG_FILE ?= data/$(area).repl.json + +# download-osm generates this file with metadata about the file +AREA_DC_CONFIG_FILE ?= data/$(area).dc-config.yml + +ifeq ($(strip $(area)),) + define assert_area_is_given + @echo "ERROR: $(AREA_ERROR)" + @echo "" + @echo " make $@ area=" + @echo "" + @echo "To download an area, use make download " + @echo "To list downloadable areas, use make list-geofabrik and/or make list-bbbike" + @exit 1 + endef +else + ifneq ($(strip $(AREA_INFO)),) + define assert_area_is_given + @echo "$(AREA_INFO)" + endef + endif +endif + + + # # TARGETS # @@ -78,6 +156,8 @@ help: @echo "Hints for developers:" @echo " make # build source code" @echo " make list-geofabrik # list actual geofabrik OSM extracts for download" + @echo " make list-bbbike # list actual BBBike OSM extracts for download" + @echo " make download area=albania # download OSM data from any source and create config file" @echo " make download-geofabrik area=albania # download OSM data from geofabrik.de and create config file" @echo " make download-osmfr area=asia/qatar # download OSM data from openstreetmap.fr and create config file" @echo " make download-bbbike area=Amsterdam # download OSM data from bbbike.org and create config file" @@ -105,7 +185,7 @@ help: .PHONY: init-dirs init-dirs: @mkdir -p build/sql - @mkdir -p data + @mkdir -p data/borders @mkdir -p cache build/openmaptiles.tm2source/data.yml: init-dirs @@ -165,29 +245,51 @@ list-geofabrik: init-dirs list-bbbike: init-dirs $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools download-osm list bbbike +# +# download, download-geofabrik, download-osmfr, and download-bbbike are handled here +# The --imposm-cfg will fail for some of the sources, but we ignore that error -- only needed for diff mode +# OSM_SERVERS := geofabrik osmfr bbbike -ALL_DOWNLOADS := $(addprefix download-,$(OSM_SERVERS)) -OSM_SERVER=$(patsubst download-%,%,$@) +ALL_DOWNLOADS := $(addprefix download-,$(OSM_SERVERS)) download +OSM_SERVER=$(patsubst download,,$(patsubst download-%,%,$@)) .PHONY: $(ALL_DOWNLOADS) $(ALL_DOWNLOADS): init-dirs -ifeq ($(strip $(area)),) - @echo "" - @echo "ERROR: Unable to download an area if area is not given." - @echo "Usage:" - @echo " make download-$(OSM_SERVER) area=" - @echo "" - $(if $(filter %-geofabrik,$@),@echo "Use make list-geofabrik to get a list of all available areas";echo "") - @exit 1 -else - @echo "=============== download-$(OSM_SERVER) =======================" - @echo "Download area: $(area)" - $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c \ - 'download-osm $(OSM_SERVER) $(area) \ + @$(assert_area_is_given) +ifeq (,$(wildcard $(PBF_FILE))) +ifneq ($(strip $(url)),) + $(if $(OSM_SERVER),$(error url parameter can only be used with the 'make download area=... url=...')) +endif + @echo "Downloading $(area) into $(PBF_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" + @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c ' \ + download-osm $(OSM_SERVER) $(DOWNLOAD_AREA) \ --minzoom $$QUICKSTART_MIN_ZOOM \ --maxzoom $$QUICKSTART_MAX_ZOOM \ - --make-dc /import/docker-compose-config.yml -- -d /import' - ls -la ./data/$(notdir $(area))* + --make-dc $(AREA_DC_CONFIG_FILE) \ + --imposm-cfg $(IMPOSM_CONFIG_FILE) \ + --output $(PBF_FILE) \ + 2>&1 \ + | tee /tmp/download.out ; \ + exit_code=$${PIPESTATUS[0]} ; \ + if [[ "$$exit_code" != "0" ]]; then \ + if grep -q "Imposm config file cannot be generated from this source" /tmp/download.out; then \ + echo "WARNING: $(IMPOSM_CONFIG_FILE) could not be generated, but it is only needed to apply updates." ; \ + else \ + exit $$exit_code ; \ + fi ; \ + fi' @echo "" +else +ifeq (,$(wildcard $(AREA_DC_CONFIG_FILE))) + @echo "Data file $(PBF_FILE) already exists, but the $(AREA_DC_CONFIG_FILE) is not, generating..." + @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c ' \ + download-osm make-dc $(PBF_FILE) \ + --minzoom $$QUICKSTART_MIN_ZOOM \ + --maxzoom $$QUICKSTART_MAX_ZOOM \ + --make-dc $(AREA_DC_CONFIG_FILE) \ + --id "$(area)"' +else + @echo "Data files $(PBF_FILE) and $(AREA_DC_CONFIG_FILE) already exists, skipping the download." +endif endif .PHONY: psql @@ -196,6 +298,7 @@ psql: start-db-nowait .PHONY: import-osm import-osm: all start-db-nowait + @$(assert_area_is_given) $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-osm $(PBF_FILE)' .PHONY: update-osm @@ -212,24 +315,28 @@ import-data: start-db .PHONY: import-borders import-borders: start-db-nowait - $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-borders $(PBF_FILE)' + @$(assert_area_is_given) + # If CSV borders file already exists, use it without re-parsing + $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c \ + 'pgwait && import-borders $$([ -f "$(BORDERS_CSV_FILE)" ] && echo 'load' || echo 'import') $(PBF_FILE)' .PHONY: import-sql import-sql: all start-db-nowait $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-sql' | \ awk -v s=": WARNING:" '$$0~s{print; print "\n*** WARNING detected, aborting"; exit(1)} 1' -.PHONY: generate-tiles -ifneq ($(wildcard data/docker-compose-config.yml),) - DC_CONFIG_TILES:=-f docker-compose.yml -f ./data/docker-compose-config.yml +ifneq ($(wildcard $(AREA_DC_CONFIG_FILE)),) + DC_CONFIG_TILES := -f docker-compose.yml -f $(AREA_DC_CONFIG_FILE) endif +.PHONY: generate-tiles generate-tiles: all start-db - rm -rf data/tiles.mbtiles - echo "Generating tiles ..."; \ + @$(assert_area_is_given) + @echo "Generating tiles into $(MBTILES_LOCAL_FILE) (will delete if already exists)..." + @rm -rf "$(MBTILES_LOCAL_FILE)" $(DOCKER_COMPOSE) $(DC_CONFIG_TILES) run $(DC_OPTS) generate-vectortiles @echo "Updating generated tile metadata ..." $(DOCKER_COMPOSE) $(DC_CONFIG_TILES) run $(DC_OPTS) openmaptiles-tools \ - mbtiles-tools meta-generate ./data/tiles.mbtiles ./openmaptiles.yaml --auto-minmax --show-ranges + mbtiles-tools meta-generate "$(MBTILES_LOCAL_FILE)" ./openmaptiles.yaml --auto-minmax --show-ranges .PHONY: start-tileserver start-tileserver: init-dirs diff --git a/README.md b/README.md index 2ebb322..a33f7f9 100644 --- a/README.md +++ b/README.md @@ -83,10 +83,10 @@ make ``` You can execute the following manual steps (for better understanding) -or use the provided `quickstart.sh` script. +or use the provided `quickstart.sh` script to automatically download and import given area. If area is not given, albania will be imported. ``` -./quickstart.sh +./quickstart.sh ``` ### Prepare the Database @@ -103,10 +103,10 @@ Import external data from [OpenStreetMapData](http://osmdata.openstreetmap.de/), make import-data ``` -[Download OpenStreetMap data extracts](http://download.geofabrik.de/) and store the PBF file in the `./data` directory. +Download OpenStreetMap data extracts from any source like [Geofabrik](http://download.geofabrik.de/), and store the PBF file in the `./data` directory. Use `download-geofabrik`, `download-bbbike`, or `download-osmfr` for a specific source. Use `download area=planet` for the entire OSM dataset (very large). Note that if you have more than one `data/*.osm.pbf` file, every `make` command will require `area=...` parameter (or you can just `export area=...` first) ```bash -make download-geofabrik area=albania +make download area=albania ``` [Import OpenStreetMap data](https://github.com/openmaptiles/openmaptiles-tools/tree/master/docker/import-osm) with the mapping rules from diff --git a/docker-compose.yml b/docker-compose.yml index 45db089..f586e1c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,10 @@ services: MAKE_DC_VERSION: "2.3" # Allow DIFF_MODE to be overwritten from shell DIFF_MODE: ${DIFF_MODE} + # Which files to use during import-borders processing + BORDERS_CLEANUP_FILE: ${BORDERS_CLEANUP_FILE} + BORDERS_PBF_FILE: ${BORDERS_PBF_FILE} + BORDERS_CSV_FILE: ${BORDERS_CSV_FILE} networks: - postgres_conn volumes: @@ -54,6 +58,10 @@ services: networks: - postgres_conn env_file: .env + environment: + FILTER_MAPNIK_OUTPUT: ${FILTER_MAPNIK_OUTPUT} + MBTILES_NAME: ${MBTILES_FILE} + IMPOSM_CONFIG_FILE: ${IMPOSM_CONFIG_FILE} generate-vectortiles: image: "openmaptiles/generate-vectortiles:${TOOLS_VERSION}" @@ -64,10 +72,12 @@ services: - postgres_conn env_file: .env environment: + FILTER_MAPNIK_OUTPUT: ${FILTER_MAPNIK_OUTPUT} + MBTILES_NAME: ${MBTILES_FILE} + IMPOSM_CONFIG_FILE: ${IMPOSM_CONFIG_FILE} BBOX: ${BBOX} MIN_ZOOM: ${MIN_ZOOM} MAX_ZOOM: ${MAX_ZOOM} - FILTER_MAPNIK_OUTPUT: ${FILTER_MAPNIK_OUTPUT} postserve: image: "openmaptiles/openmaptiles-tools:${TOOLS_VERSION}" diff --git a/quickstart.sh b/quickstart.sh index dd44a25..3c5513b 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -46,26 +46,17 @@ else fi if [ $# -eq 0 ]; then - osm_area=albania # default test country - echo "No parameter - set area=$osm_area " + # default test area + export area=albania + echo "No parameter - set area=$area " else - osm_area=$1 + export area=$1 fi if [ $# -eq 2 ]; then - osm_server=$2 -else - if [[ ${osm_area} == [[:upper:]]* ]]; then - # Only bbbike area names are capitalized - osm_server=bbbike - else - # default OSM server - osm_server=geofabrik - fi + osm_server=$2 fi -pbf_file="./data/${osm_area##*/}-latest.osm.pbf" - ## Min versions ... MIN_COMPOSE_VER=1.7.1 MIN_DOCKER_VER=1.12.3 @@ -117,8 +108,8 @@ echo " Start processing echo "-------------------------------------------------------------------------------------" echo "====> : OpenMapTiles quickstart! [ https://github.com/openmaptiles/openmaptiles ] " echo " : This will be logged to the $log_file file (for debugging) and to the screen" -echo " : Area : $osm_area " -echo " : Download Server : $osm_server " +echo " : Area : $area " +echo " : Download Server : ${osm_server:-unset (automatic)} " echo " : Preloaded Image : $USE_PRELOADED_IMAGE " echo " : Git version : $(git rev-parse HEAD) " echo " : Started : $STARTDATE " @@ -140,7 +131,7 @@ if [[ "$OSTYPE" == "linux-gnu" ]]; then exit 1 fi echo " : --- Memory, CPU info ---- " - mem=$( grep MemTotal /proc/meminfo | awk '{print $2}' | xargs -I {} echo "scale=4; {}/1024^2" | bc ) + mem=$( grep MemTotal /proc/meminfo | awk '{print $2}' | xargs -I {} echo "scale=4; {}/1024^2" | bc ) echo "system memory (GB): ${mem}" grep SwapTotal /proc/meminfo echo "cpu number: $(grep -c processor /proc/cpuinfo) x $(grep "bogomips" /proc/cpuinfo | head -1)" @@ -168,27 +159,13 @@ make init-dirs echo " " echo "-------------------------------------------------------------------------------------" -echo "====> : Removing old MBTILES if exists ( ./data/*.mbtiles ) " -rm -f ./data/*.mbtiles +echo "====> : Removing old MBTILES if exists ( ./data/${area}.mbtiles ) " +rm -f "./data/${area}.mbtiles" -if [[ ! -f "${pbf_file}" || ! -f "./data/docker-compose-config.yml" ]]; then - echo " " - echo "-------------------------------------------------------------------------------------" - echo "====> : Downloading ${osm_area} from ${osm_server}..." - rm -rf ./data/* - make download-${osm_server} "area=${osm_area}" -else - echo " " - echo "-------------------------------------------------------------------------------------" - echo "====> : The pbf file $pbf_file exists, we don't need to download!" -fi - - -if [ ! -f "${pbf_file}" ]; then - echo " " - echo "Missing $pbf_file , Download or Parameter error? " - exit 1 -fi +echo " " +echo "-------------------------------------------------------------------------------------" +echo "====> : Downloading ${area} from ${osm_server:-any source}..." +make "download${osm_server:+-${osm_server}}" echo " " echo "-------------------------------------------------------------------------------------" @@ -243,17 +220,17 @@ fi echo " " echo "-------------------------------------------------------------------------------------" -echo "====> : Start importing OpenStreetMap data: ${pbf_file} -> imposm3[./build/mapping.yaml] -> PostgreSQL" +echo "====> : Start importing OpenStreetMap data: ${area} -> imposm3[./build/mapping.yaml] -> PostgreSQL" echo " : Imposm3 documentation: https://imposm.org/docs/imposm3/latest/index.html " echo " : Thank you Omniscale! " echo " : Source code: https://github.com/openmaptiles/openmaptiles-tools/tree/master/docker/import-osm " echo " : The OpenstreetMap data license: https://www.openstreetmap.org/copyright (ODBL) " echo " : Thank you OpenStreetMap Contributors ! " -make import-osm "PBF_FILE=${pbf_file}" +make import-osm echo " " echo "-------------------------------------------------------------------------------------" -echo "====> : Start importing border data from ${pbf_file} into PostgreSQL using osmborder" +echo "====> : Start importing border ${area} data into PostgreSQL using osmborder" echo " : Source code: https://github.com/pnorman/osmborder" echo " : Data license: http://www.openstreetmap.org/copyright" echo " : Thank you: Paul Norman" @@ -288,7 +265,7 @@ echo " " echo "-------------------------------------------------------------------------------------" echo "====> : Start generating MBTiles (containing gzipped MVT PBF) from a TM2Source project. " echo " : TM2Source project definitions : ./build/openmaptiles.tm2source/data.yml " -echo " : Output MBTiles: ./data/tiles.mbtiles " +echo " : Output MBTiles: ./data/${area}.mbtiles " echo " : Source code: https://github.com/openmaptiles/openmaptiles-tools/tree/master/docker/generate-vectortiles " echo " : We are using a lot of Mapbox Open Source tools! : https://github.com/mapbox " echo " : Thank you https://www.mapbox.com !" @@ -314,11 +291,6 @@ rm -f ./data/quickstart_checklist.chk cat ./data/quickstart_checklist.chk ENDTIME=$(date +%s) -if stat --help >/dev/null 2>&1; then - MODDATE=$(stat -c %y "${pbf_file}" ) -else - MODDATE=$(stat -f%Sm -t '%F %T %z' "${pbf_file}" ) -fi echo " " echo " " @@ -333,15 +305,14 @@ docker images | grep openmaptiles echo " " echo "-------------------------------------------------------------------------------------" -echo "====> : (disk space) We have created the new vectortiles ( ./data/tiles.mbtiles ) " +echo "====> : (disk space) We have created the new vectortiles ( ./data/${area}.mbtiles ) " echo " : Please respect the licenses (OdBL for OSM data) of the sources when distributing the MBTiles file." -echo " : Created from $pbf_file ( file moddate: $MODDATE ) " -echo " : Size: " -ls -la ./data/*.mbtiles +echo " : Data directory content:" +ls -la ./data echo " " echo "-------------------------------------------------------------------------------------" -echo "The ./quickstart.sh $osm_area is finished! " +echo "The ./quickstart.sh $area is finished! " echo "It takes $((ENDTIME - STARTTIME)) seconds to complete" echo "We saved the log file to $log_file ( for debugging ) You can compare with the travis log !" echo " " From 1a9f6132c3be36a220886f6a0fe63049cd9f6f1b Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 4 Jun 2020 15:45:04 -0400 Subject: [PATCH 06/20] New generate-dc-config target, rm QUICKSTART_MIN/MAX_ZOOM (#915) * Set `MAX_ZOOM` to 7 by default. * Remove `QUICKSTART_MIN/MAX_ZOOM` - unneeded complexity with two env vars. We can just use `MIN_ZOOM` and `MAX_ZOOM`. See also #261 * Generate dc-config yaml file with a new `make generate-dc-config` step. It will compute BBOX based on the downloaded data file. This step is not needed for planet generation. * Generate Imposm replication file only when `DIFF_MODE` is `true`. Not needed otherwise. If the data source does not support it, it will throw an error. --- .env | 13 ++++++---- .github/workflows/tests.yml | 7 ++--- Makefile | 51 +++++++++++++++++++------------------ QUICKSTART.md | 17 +++++-------- README.md | 8 +++--- quickstart.sh | 11 +++++++- 6 files changed, 57 insertions(+), 50 deletions(-) diff --git a/.env b/.env index c415676..f6cb692 100644 --- a/.env +++ b/.env @@ -10,13 +10,16 @@ PGPASSWORD=openmaptiles PGHOST=postgres PGPORT=5432 -QUICKSTART_MIN_ZOOM=0 -QUICKSTART_MAX_ZOOM=7 -DIFF_MODE=false - +# BBOX may get overwritten by the computed bbox of the specific area: +# make generate-dc-config BBOX=-180.0,-85.0511,180.0,85.0511 + +# Which zooms to generate in make generate-tiles MIN_ZOOM=0 -MAX_ZOOM=14 +MAX_ZOOM=7 + +# Use true (case sensitive) to allow data updates +DIFF_MODE=false # Hide some output from Mapnik tile generation for clarity FILTER_MAPNIK_OUTPUT=1 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index abb258c..0b896b8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,12 +20,9 @@ jobs: - name: Run quickstart for a small area env: area: monaco - QUICKSTART_MIN_ZOOM: 0 - QUICKSTART_MAX_ZOOM: 14 + MIN_ZOOM: 0 + MAX_ZOOM: 14 run: | - # For now, change the quickstart values directly in the .env file - # TODO: We should probably use env vars instead - sed -i 's/QUICKSTART_MAX_ZOOM=7/QUICKSTART_MAX_ZOOM=14/g' .env export QUIET=1 ./quickstart.sh $area diff --git a/Makefile b/Makefile index 2e044fc..df2b06d 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,12 @@ endif # Set OpenMapTiles host OMT_HOST := http://$(firstword $(subst :, ,$(subst tcp://,,$(DOCKER_HOST))) localhost) +# This defines an easy $(newline) value to act as a "\n". Make sure to keep exactly two empty lines after newline. +define newline + + +endef + # # Determine area to work on @@ -161,6 +167,7 @@ help: @echo " make download-geofabrik area=albania # download OSM data from geofabrik.de and create config file" @echo " make download-osmfr area=asia/qatar # download OSM data from openstreetmap.fr and create config file" @echo " make download-bbbike area=Amsterdam # download OSM data from bbbike.org and create config file" + @echo " make generate-dc-config # scan data file and generate tile generation config file with bbox" @echo " make psql # start PostgreSQL console" @echo " make psql-list-tables # list all PostgreSQL tables" @echo " make vacuum-db # PostgreSQL: VACUUM ANALYZE" @@ -255,41 +262,35 @@ OSM_SERVER=$(patsubst download,,$(patsubst download-%,%,$@)) .PHONY: $(ALL_DOWNLOADS) $(ALL_DOWNLOADS): init-dirs @$(assert_area_is_given) -ifeq (,$(wildcard $(PBF_FILE))) ifneq ($(strip $(url)),) - $(if $(OSM_SERVER),$(error url parameter can only be used with the 'make download area=... url=...')) + $(if $(OSM_SERVER),$(error url parameter can only be used with non-specific download target:$(newline) make download area=$(area) url="$(url)"$(newline))) endif - @echo "Downloading $(area) into $(PBF_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" +ifeq (,$(wildcard $(PBF_FILE))) + @echo "Downloading $(DOWNLOAD_AREA) into $(PBF_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c ' \ - download-osm $(OSM_SERVER) $(DOWNLOAD_AREA) \ - --minzoom $$QUICKSTART_MIN_ZOOM \ - --maxzoom $$QUICKSTART_MAX_ZOOM \ - --make-dc $(AREA_DC_CONFIG_FILE) \ - --imposm-cfg $(IMPOSM_CONFIG_FILE) \ - --output $(PBF_FILE) \ - 2>&1 \ - | tee /tmp/download.out ; \ - exit_code=$${PIPESTATUS[0]} ; \ - if [[ "$$exit_code" != "0" ]]; then \ - if grep -q "Imposm config file cannot be generated from this source" /tmp/download.out; then \ - echo "WARNING: $(IMPOSM_CONFIG_FILE) could not be generated, but it is only needed to apply updates." ; \ - else \ - exit $$exit_code ; \ - fi ; \ + if [[ "$$DIFF_MODE" == "true" ]]; then \ + download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ + --imposm-cfg "$(IMPOSM_CONFIG_FILE)" \ + --output "$(PBF_FILE)" ; \ + else \ + download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ + --output "$(PBF_FILE)" ; \ fi' @echo "" else + @echo "Data files $(PBF_FILE) already exists, skipping the download." +endif + +.PHONY: generate-dc-config +generate-dc-config: + @$(assert_area_is_given) ifeq (,$(wildcard $(AREA_DC_CONFIG_FILE))) - @echo "Data file $(PBF_FILE) already exists, but the $(AREA_DC_CONFIG_FILE) is not, generating..." @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c ' \ - download-osm make-dc $(PBF_FILE) \ - --minzoom $$QUICKSTART_MIN_ZOOM \ - --maxzoom $$QUICKSTART_MAX_ZOOM \ - --make-dc $(AREA_DC_CONFIG_FILE) \ + download-osm make-dc "$(PBF_FILE)" \ + --make-dc "$(AREA_DC_CONFIG_FILE)" \ --id "$(area)"' else - @echo "Data files $(PBF_FILE) and $(AREA_DC_CONFIG_FILE) already exists, skipping the download." -endif + @echo "Configuration file $(AREA_DC_CONFIG_FILE) already exists, no need to regenerate." endif .PHONY: psql diff --git a/QUICKSTART.md b/QUICKSTART.md index a8b5f9d..46927f8 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -384,20 +384,17 @@ and the generated maps are going to be available in webbrowser on [localhost:808 This is only a quick preview, because your mbtiles only generated to zoom level 7 ! -### Change MIN_ZOOM and MAX_ZOOM +### Set which zooms to generate -modify the settings in the `.env` file, the defaults : -* QUICKSTART_MIN_ZOOM=0 -* QUICKSTART_MAX_ZOOM=7 +modify the settings in the `.env` file, the defaults: +* `MIN_ZOOM=0` +* `MAX_ZOOM=7` -and re-start `./quickstart.sh ` -* the new config file re-generating to here ./data/docker-compose-config.yml -* Known problems: - * If you use same area - then the ./data/docker-compose-config.yml not re-generating, so you have to modify by hand! +Delete the `./data/.dc-config.yml` file, and re-start `./quickstart.sh ` Hints: -* Small increments! Never starts with the MAX_ZOOM = 14 -* The suggested MAX_ZOOM = 14 - use only with small extracts +* Small increments! Never starts with the `MAX_ZOOM = 14` +* The suggested `MAX_ZOOM = 14` - use only with small extracts ### Check other commands diff --git a/README.md b/README.md index a33f7f9..1285b62 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Import external data from [OpenStreetMapData](http://osmdata.openstreetmap.de/), make import-data ``` -Download OpenStreetMap data extracts from any source like [Geofabrik](http://download.geofabrik.de/), and store the PBF file in the `./data` directory. Use `download-geofabrik`, `download-bbbike`, or `download-osmfr` for a specific source. Use `download area=planet` for the entire OSM dataset (very large). Note that if you have more than one `data/*.osm.pbf` file, every `make` command will require `area=...` parameter (or you can just `export area=...` first) +Download OpenStreetMap data extracts from any source like [Geofabrik](http://download.geofabrik.de/), and store the PBF file in the `./data` directory. To use a specific download source, use `download-geofabrik`, `download-bbbike`, or `download-osmfr`, or use `download` to make it auto-pick the area. You can use `area=planet` for the entire OSM dataset (very large). Note that if you have more than one `data/*.osm.pbf` file, every `make` command will always require `area=...` parameter (or you can just `export area=...` first). ```bash make download area=albania @@ -135,11 +135,11 @@ make make import-sql ``` -Now you are ready to **generate the vector tiles**. Using environment variables -you can limit the bounding box and zoom levels of what you want to generate (`docker-compose.yml`). +Now you are ready to **generate the vector tiles**. By default, `./.env` specifies the entire planet BBOX for zooms 0-7, but running `generate-dc-config` will analyze the data file and set the `BBOX` param to limit tile generation. It will also modify `MIN_ZOOM` and `MAX_ZOOM` values based on the .env, but can be changed. ``` -make generate-tiles +make generate-dc-config # compute data bbox -- not needed for the whole planet +make generate-tiles # generate tiles ``` ## License diff --git a/quickstart.sh b/quickstart.sh index 3c5513b..6b0e90c 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -33,7 +33,7 @@ set -o nounset # ./quickstart.sh Adelaide bbbike # .... # -# to list geofabrik areas: make download-geofabrik-list +# to list geofabrik areas: make list-geofabrik or make list-bbbike # see more QUICKSTART.md # @@ -261,6 +261,15 @@ echo "-------------------------------------------------------------------------- echo "====> : Testing PostgreSQL tables to match layer definitions metadata" make test-perf-null +echo " " +echo "-------------------------------------------------------------------------------------" +if [[ "$area" != "planet" ]]; then + echo "====> : Compute bounding box for tile generation" + make generate-dc-config +else + echo "====> : Skipping bbox calculation when generating the entire planet" +fi + echo " " echo "-------------------------------------------------------------------------------------" echo "====> : Start generating MBTiles (containing gzipped MVT PBF) from a TM2Source project. " From 805d95df09c85880498d96d044122ea3f2d5e81d Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 5 Jun 2020 12:48:48 -0400 Subject: [PATCH 07/20] Fix import-borders if runs multiple times (#916) Running './quickstart monaco' twice in a row will cause an error the second time. --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index df2b06d..fff3e29 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ ifeq ($(strip $(area)),) # if $area is not set. set it to the name of the *.osm.pbf file, but only if there is only one data_files := $(wildcard data/*.osm.pbf) ifneq ($(word 2,$(data_files)),) - AREA_ERROR := The 'area' parameter (or env var) has not been set, and there are more than one data/*.osm.pbf files. Set area to one of these IDs, or a new one: $(patsubst data/%.osm.pbf,'%',$(data_files)) + AREA_ERROR := The 'area' parameter (or env var) has not been set, and there are more than one data/*.osm.pbf files: $(patsubst data/%.osm.pbf,'%',$(data_files)) else ifeq ($(word 1,$(data_files)),) AREA_ERROR := The 'area' parameter (or env var) has not been set, and there are no data/*.osm.pbf files @@ -121,6 +121,7 @@ AREA_DC_CONFIG_FILE ?= data/$(area).dc-config.yml ifeq ($(strip $(area)),) define assert_area_is_given + @echo "" @echo "ERROR: $(AREA_ERROR)" @echo "" @echo " make $@ area=" @@ -319,7 +320,7 @@ import-borders: start-db-nowait @$(assert_area_is_given) # If CSV borders file already exists, use it without re-parsing $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c \ - 'pgwait && import-borders $$([ -f "$(BORDERS_CSV_FILE)" ] && echo 'load' || echo 'import') $(PBF_FILE)' + 'pgwait && import-borders $$([ -f "$(BORDERS_CSV_FILE)" ] && echo load $(BORDERS_CSV_FILE) || echo import $(PBF_FILE))' .PHONY: import-sql import-sql: all start-db-nowait From 6457419e0d3c16391a030b32541e0334ac9e614b Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 8 Jun 2020 12:19:55 -0400 Subject: [PATCH 08/20] NOOP: Format all layer's SQL code (#917) I would like to reformat all of our SQL to have a concise coding style. This makes it far easier to understand the code for a casual contributor, and lets us spot errors more easily. Most importantly, it makes it much easier to grep (search) the code because it is more likely to be in the same syntax Some key changes: * SQL keywords are always UPPERCASE, e.g. `SELECT WHEN AS END ...` * types, variables, aliases, and field names (identifiers) are always lower case * `LANGUAGE 'plpgsql'` is now `LANGUAGE plpgsql` (no quotes) * a few minor spacing/semicolon cleanups P.S. Per @TomPohys request, `TABLE` is spelled using upper case despite being a type for consistency with PG Docs. Same for `LANGUAGE SQL` vs `LANGUAGE plpgsql`. --- layers/aerodrome_label/layer.sql | 67 +- .../update_aerodrome_label_point.sql | 53 +- layers/aeroway/layer.sql | 95 +- layers/boundary/boundary.sql | 902 ++++++++------ layers/boundary/mapping.yaml | 1 - layers/building/building.sql | 190 +-- layers/housenumber/housenumber_centroid.sql | 56 +- layers/housenumber/layer.sql | 24 +- layers/landcover/landcover.sql | 266 +++-- layers/landuse/landuse.sql | 281 +++-- layers/mountain_peak/layer.sql | 92 +- layers/mountain_peak/update_peak_point.sql | 47 +- layers/park/layer.sql | 457 +++++-- layers/park/update_park_polygon.sql | 164 +-- layers/place/capital.sql | 17 +- layers/place/city.sql | 123 +- layers/place/island_rank.sql | 21 +- layers/place/layer.sql | 237 ++-- layers/place/types.sql | 16 +- layers/place/update_city_point.sql | 113 +- layers/place/update_continent_point.sql | 47 +- layers/place/update_country_point.sql | 167 +-- layers/place/update_island_point.sql | 47 +- layers/place/update_island_polygon.sql | 51 +- layers/place/update_state_point.sql | 100 +- layers/poi/class.sql | 74 +- layers/poi/layer.sql | 163 +-- layers/poi/poi_stop_agg.sql | 56 +- layers/poi/public_transport_stop_type.sql | 21 +- layers/poi/update_poi_point.sql | 88 +- layers/poi/update_poi_polygon.sql | 76 +- layers/transportation/class.sql | 75 +- layers/transportation/layer.sql | 1059 +++++++++++------ .../update_transportation_merge.sql | 178 +-- layers/transportation_name/layer.sql | 272 +++-- layers/transportation_name/network_type.sql | 31 +- .../update_route_member.sql | 92 +- .../update_transportation_name.sql | 288 +++-- layers/water/water.sql | 756 ++++++------ layers/water_name/layer.sql | 91 +- layers/water_name/update_marine_point.sql | 82 +- layers/water_name/update_water_lakeline.sql | 81 +- layers/water_name/update_water_point.sql | 79 +- layers/waterway/update_important_waterway.sql | 244 ++-- .../waterway/update_waterway_linestring.sql | 40 +- layers/waterway/waterway.sql | 286 +++-- 46 files changed, 4642 insertions(+), 3124 deletions(-) diff --git a/layers/aerodrome_label/layer.sql b/layers/aerodrome_label/layer.sql index 19e9bac..fd49267 100644 --- a/layers/aerodrome_label/layer.sql +++ b/layers/aerodrome_label/layer.sql @@ -1,41 +1,42 @@ - -- etldoc: layer_aerodrome_label[shape=record fillcolor=lightpink, style="rounded,filled", label="layer_aerodrome_label | z10+" ] ; -CREATE OR REPLACE FUNCTION layer_aerodrome_label( - bbox geometry, - zoom_level integer, - pixel_width numeric) - RETURNS TABLE( - osm_id bigint, - geometry geometry, - name text, - name_en text, - name_de text, - tags hstore, - class text, - iata text, - icao text, - ele int, - ele_ft int) AS +CREATE OR REPLACE FUNCTION layer_aerodrome_label(bbox geometry, + zoom_level integer, + pixel_width numeric) + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + class text, + iata text, + icao text, + ele int, + ele_ft int + ) +AS $$ - -- etldoc: osm_aerodrome_label_point -> layer_aerodrome_label:z10_ - SELECT +SELECT + -- etldoc: osm_aerodrome_label_point -> layer_aerodrome_label:z10_ osm_id, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, tags, CASE - %%FIELD_MAPPING: class %% - ELSE 'other' - END AS class, - NULLIF(iata, '') AS iata, - NULLIF(icao, '') AS icao, - substring(ele from E'^(-?\\d+)(\\D|$)')::int AS ele, - round(substring(ele from E'^(-?\\d+)(\\D|$)')::int*3.2808399)::int AS ele_ft - FROM osm_aerodrome_label_point - WHERE geometry && bbox AND zoom_level >= 10; -$$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; + %%FIELD_MAPPING: class %% + ELSE 'other' + END AS class, + NULLIF(iata, '') AS iata, + NULLIF(icao, '') AS icao, + substring(ele FROM E'^(-?\\d+)(\\D|$)')::int AS ele, + round(substring(ele FROM E'^(-?\\d+)(\\D|$)')::int * 3.2808399)::int AS ele_ft +FROM osm_aerodrome_label_point +WHERE geometry && bbox + AND zoom_level >= 10; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/aerodrome_label/update_aerodrome_label_point.sql b/layers/aerodrome_label/update_aerodrome_label_point.sql index 541d7ba..e730b51 100644 --- a/layers/aerodrome_label/update_aerodrome_label_point.sql +++ b/layers/aerodrome_label/update_aerodrome_label_point.sql @@ -2,15 +2,16 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_aerodrome_label_point; DROP TRIGGER IF EXISTS trigger_refresh ON aerodrome_label.updates; -- etldoc: osm_aerodrome_label_point -> osm_aerodrome_label_point -CREATE OR REPLACE FUNCTION update_aerodrome_label_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_aerodrome_label_point() RETURNS void AS +$$ BEGIN - UPDATE osm_aerodrome_label_point - SET geometry = ST_Centroid(geometry) - WHERE ST_GeometryType(geometry) <> 'ST_Point'; + UPDATE osm_aerodrome_label_point + SET geometry = ST_Centroid(geometry) + WHERE ST_GeometryType(geometry) <> 'ST_Point'; - UPDATE osm_aerodrome_label_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_aerodrome_label_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -20,32 +21,40 @@ SELECT update_aerodrome_label_point(); CREATE SCHEMA IF NOT EXISTS aerodrome_label; -CREATE TABLE IF NOT EXISTS aerodrome_label.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION aerodrome_label.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS aerodrome_label.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION aerodrome_label.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO aerodrome_label.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO aerodrome_label.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION aerodrome_label.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh aerodrome_label'; PERFORM update_aerodrome_label_point(); + -- noinspection SqlWithoutWhere DELETE FROM aerodrome_label.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_aerodrome_label_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_aerodrome_label_point FOR EACH STATEMENT - EXECUTE PROCEDURE aerodrome_label.flag(); +EXECUTE PROCEDURE aerodrome_label.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON aerodrome_label.updates + AFTER INSERT + ON aerodrome_label.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE aerodrome_label.refresh(); +EXECUTE PROCEDURE aerodrome_label.refresh(); diff --git a/layers/aeroway/layer.sql b/layers/aeroway/layer.sql index 1116c67..6863010 100644 --- a/layers/aeroway/layer.sql +++ b/layers/aeroway/layer.sql @@ -2,44 +2,59 @@ -- etldoc: label="layer_aeroway | z10| z11| z12| z13| z14+" ]; CREATE OR REPLACE FUNCTION layer_aeroway(bbox geometry, zoom_level int) -RETURNS TABLE(geometry geometry, class text, ref text) AS $$ - SELECT geometry, aeroway AS class, ref FROM ( - -- etldoc: osm_aeroway_linestring_gen3 -> layer_aeroway:z10 - SELECT geometry, aeroway, ref - FROM osm_aeroway_linestring_gen3 WHERE zoom_level = 10 - UNION ALL - -- etldoc: osm_aeroway_linestring_gen2 -> layer_aeroway:z11 - SELECT geometry, aeroway, ref - FROM osm_aeroway_linestring_gen2 WHERE zoom_level = 11 - UNION ALL - -- etldoc: osm_aeroway_linestring_gen1 -> layer_aeroway:z12 - SELECT geometry, aeroway, ref - FROM osm_aeroway_linestring_gen1 WHERE zoom_level = 12 - UNION ALL - -- etldoc: osm_aeroway_linestring -> layer_aeroway:z13 - -- etldoc: osm_aeroway_linestring -> layer_aeroway:z14_ - SELECT geometry, aeroway, ref - FROM osm_aeroway_linestring WHERE zoom_level >= 13 - UNION ALL - - -- etldoc: osm_aeroway_polygon_gen3 -> layer_aeroway:z10 - -- etldoc: osm_aeroway_polygon_gen3 -> layer_aeroway:z11 - SELECT geometry, aeroway, ref - FROM osm_aeroway_polygon_gen3 WHERE zoom_level BETWEEN 10 AND 11 - UNION ALL - -- etldoc: osm_aeroway_polygon_gen2 -> layer_aeroway:z12 - SELECT geometry, aeroway, ref - FROM osm_aeroway_polygon_gen2 WHERE zoom_level = 12 - UNION ALL - -- etldoc: osm_aeroway_polygon_gen1 -> layer_aeroway:z13 - SELECT geometry, aeroway, ref - FROM osm_aeroway_polygon_gen1 WHERE zoom_level = 13 - UNION ALL - -- etldoc: osm_aeroway_polygon -> layer_aeroway:z14_ - SELECT geometry, aeroway, ref - FROM osm_aeroway_polygon WHERE zoom_level >= 14 - ) AS zoom_levels - WHERE geometry && bbox; + RETURNS TABLE + ( + geometry geometry, + class text, + ref text + ) +AS $$ -LANGUAGE SQL IMMUTABLE -PARALLEL SAFE; +SELECT geometry, aeroway AS class, ref +FROM ( + -- etldoc: osm_aeroway_linestring_gen3 -> layer_aeroway:z10 + SELECT geometry, aeroway, ref + FROM osm_aeroway_linestring_gen3 + WHERE zoom_level = 10 + UNION ALL + -- etldoc: osm_aeroway_linestring_gen2 -> layer_aeroway:z11 + SELECT geometry, aeroway, ref + FROM osm_aeroway_linestring_gen2 + WHERE zoom_level = 11 + UNION ALL + -- etldoc: osm_aeroway_linestring_gen1 -> layer_aeroway:z12 + SELECT geometry, aeroway, ref + FROM osm_aeroway_linestring_gen1 + WHERE zoom_level = 12 + UNION ALL + -- etldoc: osm_aeroway_linestring -> layer_aeroway:z13 + -- etldoc: osm_aeroway_linestring -> layer_aeroway:z14_ + SELECT geometry, aeroway, ref + FROM osm_aeroway_linestring + WHERE zoom_level >= 13 + UNION ALL + + -- etldoc: osm_aeroway_polygon_gen3 -> layer_aeroway:z10 + -- etldoc: osm_aeroway_polygon_gen3 -> layer_aeroway:z11 + SELECT geometry, aeroway, ref + FROM osm_aeroway_polygon_gen3 + WHERE zoom_level BETWEEN 10 AND 11 + UNION ALL + -- etldoc: osm_aeroway_polygon_gen2 -> layer_aeroway:z12 + SELECT geometry, aeroway, ref + FROM osm_aeroway_polygon_gen2 + WHERE zoom_level = 12 + UNION ALL + -- etldoc: osm_aeroway_polygon_gen1 -> layer_aeroway:z13 + SELECT geometry, aeroway, ref + FROM osm_aeroway_polygon_gen1 + WHERE zoom_level = 13 + UNION ALL + -- etldoc: osm_aeroway_polygon -> layer_aeroway:z14_ + SELECT geometry, aeroway, ref + FROM osm_aeroway_polygon + WHERE zoom_level >= 14 + ) AS zoom_levels +WHERE geometry && bbox; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/boundary/boundary.sql b/layers/boundary/boundary.sql index e0705c9..bf75716 100644 --- a/layers/boundary/boundary.sql +++ b/layers/boundary/boundary.sql @@ -1,475 +1,629 @@ -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen1 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen1 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen1 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen1 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen1 AS ( - SELECT ST_Simplify(geometry, 10) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 10 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen1 AS +( +SELECT ST_Simplify(geometry, 10) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 10 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen1_idx ON osm_border_linestring_gen1 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen2 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen2 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen2 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen2 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen2 AS ( - SELECT ST_Simplify(geometry, 20) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 10 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen2 AS +( +SELECT ST_Simplify(geometry, 20) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 10 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen2_idx ON osm_border_linestring_gen2 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen3 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen3 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen3 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen3 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen3 AS ( - SELECT ST_Simplify(geometry, 40) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 8 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen3 AS +( +SELECT ST_Simplify(geometry, 40) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 8 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen3_idx ON osm_border_linestring_gen3 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen4 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen4 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen4 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen4 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen4 AS ( - SELECT ST_Simplify(geometry, 80) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 6 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen4 AS +( +SELECT ST_Simplify(geometry, 80) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 6 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen4_idx ON osm_border_linestring_gen4 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen5 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen5 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen5 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen5 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen5 AS ( - SELECT ST_Simplify(geometry, 160) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 6 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen5 AS +( +SELECT ST_Simplify(geometry, 160) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 6 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen5_idx ON osm_border_linestring_gen5 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen6 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen6 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen6 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen6 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen6 AS ( - SELECT ST_Simplify(geometry, 300) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 4 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen6 AS +( +SELECT ST_Simplify(geometry, 300) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 4 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen6_idx ON osm_border_linestring_gen6 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen7 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen7 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen7 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen7 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen7 AS ( - SELECT ST_Simplify(geometry, 600) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 4 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen7 AS +( +SELECT ST_Simplify(geometry, 600) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 4 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen7_idx ON osm_border_linestring_gen7 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen8 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen8 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen8 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen8 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen8 AS ( - SELECT ST_Simplify(geometry, 1200) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 4 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen8 AS +( +SELECT ST_Simplify(geometry, 1200) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 4 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen8_idx ON osm_border_linestring_gen8 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen9 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen9 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen9 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen9 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen9 AS ( - SELECT ST_Simplify(geometry, 2400) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 4 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen9 AS +( +SELECT ST_Simplify(geometry, 2400) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 4 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen9_idx ON osm_border_linestring_gen9 USING gist (geometry); -- This statement can be deleted after the border importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_border_linestring_gen10 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_border_linestring_gen10 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_border_linestring -> osm_border_linestring_gen10 DROP MATERIALIZED VIEW IF EXISTS osm_border_linestring_gen10 CASCADE; -CREATE MATERIALIZED VIEW osm_border_linestring_gen10 AS ( - SELECT ST_Simplify(geometry, 4800) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime - FROM osm_border_linestring - WHERE admin_level <= 2 -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_border_linestring_gen10 AS +( +SELECT ST_Simplify(geometry, 4800) AS geometry, osm_id, admin_level, dividing_line, disputed, maritime +FROM osm_border_linestring +WHERE admin_level <= 2 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_border_linestring_gen10_idx ON osm_border_linestring_gen10 USING gist (geometry); -CREATE OR REPLACE FUNCTION edit_name(name VARCHAR) RETURNS TEXT AS $$ - SELECT CASE - WHEN POSITION(' at ' in name) > 0 - THEN replace(SUBSTRING(name, POSITION(' at ' in name)+4), ' ', '') - ELSE replace(replace(name,' ',''),'Extentof','') - END; +CREATE OR REPLACE FUNCTION edit_name(name varchar) RETURNS text AS +$$ +SELECT CASE + WHEN POSITION(' at ' IN name) > 0 + THEN replace(SUBSTRING(name, POSITION(' at ' IN name) + 4), ' ', '') + ELSE replace(replace(name, ' ', ''), 'Extentof', '') + END; $$ LANGUAGE SQL IMMUTABLE; -- etldoc: ne_110m_admin_0_boundary_lines_land -> boundary_z0 -CREATE OR REPLACE VIEW boundary_z0 AS ( - SELECT geometry, - 2 AS admin_level, - (CASE WHEN featurecla LIKE 'Disputed%' THEN true ELSE false END) AS disputed, - NULL::text AS disputed_name, - NULL::text AS claimed_by, - false AS maritime - FROM ne_110m_admin_0_boundary_lines_land -); +CREATE OR REPLACE VIEW boundary_z0 AS +( +SELECT geometry, + 2 AS admin_level, + (CASE WHEN featurecla LIKE 'Disputed%' THEN TRUE ELSE FALSE END) AS disputed, + NULL::text AS disputed_name, + NULL::text AS claimed_by, + FALSE AS maritime +FROM ne_110m_admin_0_boundary_lines_land + ); -- etldoc: ne_50m_admin_0_boundary_lines_land -> boundary_z1 -- etldoc: ne_50m_admin_1_states_provinces_lines -> boundary_z1 -- etldoc: osm_border_disp_linestring_gen11 -> boundary_z1 -CREATE OR REPLACE VIEW boundary_z1 AS ( - SELECT geometry, - 2 AS admin_level, - (CASE WHEN featurecla LIKE 'Disputed%' THEN true ELSE false END) AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_50m_admin_0_boundary_lines_land - UNION ALL - SELECT geometry, - 4 AS admin_level, - false AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_50m_admin_1_states_provinces_lines - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen11 -); +CREATE OR REPLACE VIEW boundary_z1 AS +( +SELECT geometry, + 2 AS admin_level, + (CASE WHEN featurecla LIKE 'Disputed%' THEN TRUE ELSE FALSE END) AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_50m_admin_0_boundary_lines_land +UNION ALL +SELECT geometry, + 4 AS admin_level, + FALSE AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_50m_admin_1_states_provinces_lines +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen11 + ); -- etldoc: ne_50m_admin_0_boundary_lines_land -> boundary_z3 -- etldoc: ne_50m_admin_1_states_provinces_lines -> boundary_z3 -- etldoc: osm_border_disp_linestring_gen11 -> boundary_z3 -CREATE OR REPLACE VIEW boundary_z3 AS ( - SELECT geometry, - 2 AS admin_level, - (CASE WHEN featurecla LIKE 'Disputed%' THEN true ELSE false END) AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_50m_admin_0_boundary_lines_land - UNION ALL - SELECT geometry, - 4 AS admin_level, - false AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_50m_admin_1_states_provinces_lines - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen11 -); +CREATE OR REPLACE VIEW boundary_z3 AS +( +SELECT geometry, + 2 AS admin_level, + (CASE WHEN featurecla LIKE 'Disputed%' THEN TRUE ELSE FALSE END) AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_50m_admin_0_boundary_lines_land +UNION ALL +SELECT geometry, + 4 AS admin_level, + FALSE AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_50m_admin_1_states_provinces_lines +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen11 + ); -- etldoc: ne_10m_admin_0_boundary_lines_land -> boundary_z4 -- etldoc: ne_10m_admin_1_states_provinces_lines -> boundary_z4 -- etldoc: osm_border_linestring_gen10 -> boundary_z4 -- etldoc: osm_border_disp_linestring_gen10 -> boundary_z4 -CREATE OR REPLACE VIEW boundary_z4 AS ( - SELECT geometry, - 2 AS admin_level, - (CASE WHEN featurecla LIKE 'Disputed%' THEN true ELSE false END) AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_10m_admin_0_boundary_lines_land - WHERE featurecla <> 'Lease limit' - UNION ALL - SELECT geometry, - 4 AS admin_level, - false AS disputed, - NULL AS disputed_name, - NULL AS claimed_by, - false AS maritime - FROM ne_10m_admin_1_states_provinces_lines - WHERE min_zoom <= 5 - UNION ALL - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen10 - WHERE maritime=true AND admin_level <= 2 - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen10 -); +CREATE OR REPLACE VIEW boundary_z4 AS +( +SELECT geometry, + 2 AS admin_level, + (CASE WHEN featurecla LIKE 'Disputed%' THEN TRUE ELSE FALSE END) AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_10m_admin_0_boundary_lines_land +WHERE featurecla <> 'Lease limit' +UNION ALL +SELECT geometry, + 4 AS admin_level, + FALSE AS disputed, + NULL AS disputed_name, + NULL AS claimed_by, + FALSE AS maritime +FROM ne_10m_admin_1_states_provinces_lines +WHERE min_zoom <= 5 +UNION ALL +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen10 +WHERE maritime = TRUE + AND admin_level <= 2 +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen10 + ); -- etldoc: osm_border_linestring_gen9 -> boundary_z5 -- etldoc: osm_border_disp_linestring_gen9 -> boundary_z5 -CREATE OR REPLACE VIEW boundary_z5 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen9 - WHERE admin_level <= 4 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen9) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen9 -); +CREATE OR REPLACE VIEW boundary_z5 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen9 +WHERE admin_level <= 4 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen9) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen9 + ); -- etldoc: osm_border_linestring_gen8 -> boundary_z6 -- etldoc: osm_border_disp_linestring_gen8 -> boundary_z6 -CREATE OR REPLACE VIEW boundary_z6 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen8 - WHERE admin_level <= 4 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen8) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen8 -); +CREATE OR REPLACE VIEW boundary_z6 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen8 +WHERE admin_level <= 4 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen8) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen8 + ); -- etldoc: osm_border_linestring_gen7 -> boundary_z7 -- etldoc: osm_border_disp_linestring_gen7 -> boundary_z7 -CREATE OR REPLACE VIEW boundary_z7 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen7 - WHERE admin_level <= 6 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen7) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen7 -); +CREATE OR REPLACE VIEW boundary_z7 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen7 +WHERE admin_level <= 6 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen7) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen7 + ); -- etldoc: osm_border_linestring_gen6 -> boundary_z8 -- etldoc: osm_border_disp_linestring_gen6 -> boundary_z8 -CREATE OR REPLACE VIEW boundary_z8 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen6 - WHERE admin_level <= 6 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen6) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen6 -); +CREATE OR REPLACE VIEW boundary_z8 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen6 +WHERE admin_level <= 6 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen6) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen6 + ); -- etldoc: osm_border_linestring_gen5 -> boundary_z9 -- etldoc: osm_border_disp_linestring_gen5 -> boundary_z9 -CREATE OR REPLACE VIEW boundary_z9 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen5 - WHERE admin_level <= 6 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen5) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen5 -); +CREATE OR REPLACE VIEW boundary_z9 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen5 +WHERE admin_level <= 6 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen5) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen5 + ); -- etldoc: osm_border_linestring_gen4 -> boundary_z10 -- etldoc: osm_border_disp_linestring_gen4 -> boundary_z10 -CREATE OR REPLACE VIEW boundary_z10 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen4 - WHERE admin_level <= 6 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen4) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen4 -); +CREATE OR REPLACE VIEW boundary_z10 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen4 +WHERE admin_level <= 6 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen4) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen4 + ); -- etldoc: osm_border_linestring_gen3 -> boundary_z11 -- etldoc: osm_border_disp_linestring_gen3 -> boundary_z11 -CREATE OR REPLACE VIEW boundary_z11 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen3 - WHERE admin_level <= 8 - AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen3) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen3 -); +CREATE OR REPLACE VIEW boundary_z11 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen3 +WHERE admin_level <= 8 + AND osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen3) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen3 + ); -- etldoc: osm_border_linestring_gen2 -> boundary_z12 -- etldoc: osm_border_disp_linestring_gen2 -> boundary_z12 -CREATE OR REPLACE VIEW boundary_z12 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen2 - WHERE osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen2) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen2 -); +CREATE OR REPLACE VIEW boundary_z12 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen2 +WHERE osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen2) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen2 + ); -- etldoc: osm_border_linestring_gen1 -> boundary_z13 -- etldoc: osm_border_disp_linestring_gen1 -> boundary_z13 -CREATE OR REPLACE VIEW boundary_z13 AS ( - SELECT geometry, - admin_level, - disputed, - NULL AS disputed_name, - NULL AS claimed_by, - maritime - FROM osm_border_linestring_gen1 - WHERE osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen1) - UNION ALL - SELECT geometry, - admin_level, - true AS disputed, - edit_name(name) AS disputed_name, - claimed_by, - maritime - FROM osm_border_disp_linestring_gen1 -); +CREATE OR REPLACE VIEW boundary_z13 AS +( +SELECT geometry, + admin_level, + disputed, + NULL AS disputed_name, + NULL AS claimed_by, + maritime +FROM osm_border_linestring_gen1 +WHERE osm_id NOT IN (SELECT DISTINCT osm_id FROM osm_border_disp_linestring_gen1) +UNION ALL +SELECT geometry, + admin_level, + TRUE AS disputed, + edit_name(name) AS disputed_name, + claimed_by, + maritime +FROM osm_border_disp_linestring_gen1 + ); -- etldoc: layer_boundary[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label=" layer_boundary | z0 | z1_2 | z3 | z4 | z5 | z6 | z7 | z8 | z9 | z10 | z11 | z12| z13+"] -CREATE OR REPLACE FUNCTION layer_boundary (bbox geometry, zoom_level int) -RETURNS TABLE(geometry geometry, admin_level int, disputed int, disputed_name text, claimed_by text, maritime int) AS $$ - SELECT geometry, admin_level, disputed::int, disputed_name, claimed_by, maritime::int FROM ( - -- etldoc: boundary_z0 -> layer_boundary:z0 - SELECT * FROM boundary_z0 WHERE geometry && bbox AND zoom_level = 0 - UNION ALL - -- etldoc: boundary_z1 -> layer_boundary:z1_2 - SELECT * FROM boundary_z1 WHERE geometry && bbox AND zoom_level BETWEEN 1 AND 2 - UNION ALL - -- etldoc: boundary_z3 -> layer_boundary:z3 - SELECT * FROM boundary_z3 WHERE geometry && bbox AND zoom_level = 3 - UNION ALL - -- etldoc: boundary_z4 -> layer_boundary:z4 - SELECT * FROM boundary_z4 WHERE geometry && bbox AND zoom_level = 4 - UNION ALL - -- etldoc: boundary_z5 -> layer_boundary:z5 - SELECT * FROM boundary_z5 WHERE geometry && bbox AND zoom_level = 5 - UNION ALL - -- etldoc: boundary_z6 -> layer_boundary:z6 - SELECT * FROM boundary_z6 WHERE geometry && bbox AND zoom_level = 6 - UNION ALL - -- etldoc: boundary_z7 -> layer_boundary:z7 - SELECT * FROM boundary_z7 WHERE geometry && bbox AND zoom_level = 7 - UNION ALL - -- etldoc: boundary_z8 -> layer_boundary:z8 - SELECT * FROM boundary_z8 WHERE geometry && bbox AND zoom_level = 8 - UNION ALL - -- etldoc: boundary_z9 -> layer_boundary:z9 - SELECT * FROM boundary_z9 WHERE geometry && bbox AND zoom_level = 9 - UNION ALL - -- etldoc: boundary_z10 -> layer_boundary:z10 - SELECT * FROM boundary_z10 WHERE geometry && bbox AND zoom_level = 10 - UNION ALL - -- etldoc: boundary_z11 -> layer_boundary:z11 - SELECT * FROM boundary_z11 WHERE geometry && bbox AND zoom_level = 11 - UNION ALL - -- etldoc: boundary_z12 -> layer_boundary:z12 - SELECT * FROM boundary_z12 WHERE geometry && bbox AND zoom_level = 12 - UNION ALL - -- etldoc: boundary_z13 -> layer_boundary:z13 - SELECT * FROM boundary_z13 WHERE geometry && bbox AND zoom_level >= 13 - ) AS zoom_levels; +CREATE OR REPLACE FUNCTION layer_boundary(bbox geometry, zoom_level int) + RETURNS TABLE + ( + geometry geometry, + admin_level int, + disputed int, + disputed_name text, + claimed_by text, + maritime int + ) +AS $$ -LANGUAGE SQL IMMUTABLE -PARALLEL SAFE; +SELECT geometry, admin_level, disputed::int, disputed_name, claimed_by, maritime::int +FROM ( + -- etldoc: boundary_z0 -> layer_boundary:z0 + SELECT * + FROM boundary_z0 + WHERE geometry && bbox + AND zoom_level = 0 + UNION ALL + -- etldoc: boundary_z1 -> layer_boundary:z1_2 + SELECT * + FROM boundary_z1 + WHERE geometry && bbox + AND zoom_level BETWEEN 1 AND 2 + UNION ALL + -- etldoc: boundary_z3 -> layer_boundary:z3 + SELECT * + FROM boundary_z3 + WHERE geometry && bbox + AND zoom_level = 3 + UNION ALL + -- etldoc: boundary_z4 -> layer_boundary:z4 + SELECT * + FROM boundary_z4 + WHERE geometry && bbox + AND zoom_level = 4 + UNION ALL + -- etldoc: boundary_z5 -> layer_boundary:z5 + SELECT * + FROM boundary_z5 + WHERE geometry && bbox + AND zoom_level = 5 + UNION ALL + -- etldoc: boundary_z6 -> layer_boundary:z6 + SELECT * + FROM boundary_z6 + WHERE geometry && bbox + AND zoom_level = 6 + UNION ALL + -- etldoc: boundary_z7 -> layer_boundary:z7 + SELECT * + FROM boundary_z7 + WHERE geometry && bbox + AND zoom_level = 7 + UNION ALL + -- etldoc: boundary_z8 -> layer_boundary:z8 + SELECT * + FROM boundary_z8 + WHERE geometry && bbox + AND zoom_level = 8 + UNION ALL + -- etldoc: boundary_z9 -> layer_boundary:z9 + SELECT * + FROM boundary_z9 + WHERE geometry && bbox + AND zoom_level = 9 + UNION ALL + -- etldoc: boundary_z10 -> layer_boundary:z10 + SELECT * + FROM boundary_z10 + WHERE geometry && bbox + AND zoom_level = 10 + UNION ALL + -- etldoc: boundary_z11 -> layer_boundary:z11 + SELECT * + FROM boundary_z11 + WHERE geometry && bbox + AND zoom_level = 11 + UNION ALL + -- etldoc: boundary_z12 -> layer_boundary:z12 + SELECT * + FROM boundary_z12 + WHERE geometry && bbox + AND zoom_level = 12 + UNION ALL + -- etldoc: boundary_z13 -> layer_boundary:z13 + SELECT * + FROM boundary_z13 + WHERE geometry && bbox + AND zoom_level >= 13 + ) AS zoom_levels; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/boundary/mapping.yaml b/layers/boundary/mapping.yaml index aacb1b5..0acc08a 100644 --- a/layers/boundary/mapping.yaml +++ b/layers/boundary/mapping.yaml @@ -110,4 +110,3 @@ tables: #admin_level: ['2'] admin_level: [__any__] claimed_by: [__any__] - diff --git a/layers/building/building.sql b/layers/building/building.sql index 5a99017..85025d9 100644 --- a/layers/building/building.sql +++ b/layers/building/building.sql @@ -1,95 +1,117 @@ -- etldoc: layer_building[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_building | z13 | z14+ " ] ; -CREATE INDEX IF NOT EXISTS osm_building_relation_building_idx ON osm_building_relation(building) WHERE building = '' AND ST_GeometryType(geometry) = 'ST_Polygon'; -CREATE INDEX IF NOT EXISTS osm_building_relation_member_idx ON osm_building_relation(member) WHERE role = 'outline'; +CREATE INDEX IF NOT EXISTS osm_building_relation_building_idx ON osm_building_relation (building) WHERE building = '' AND ST_GeometryType(geometry) = 'ST_Polygon'; +CREATE INDEX IF NOT EXISTS osm_building_relation_member_idx ON osm_building_relation (member) WHERE role = 'outline'; -CREATE OR REPLACE VIEW osm_all_buildings AS ( - -- etldoc: osm_building_relation -> layer_building:z14_ - -- Buildings built from relations - SELECT member AS osm_id, geometry, - COALESCE(CleanNumeric(height), CleanNumeric(buildingheight)) as height, - COALESCE(CleanNumeric(min_height), CleanNumeric(buildingmin_height)) as min_height, - COALESCE(CleanNumeric(levels), CleanNumeric(buildinglevels)) as levels, - COALESCE(CleanNumeric(min_level), CleanNumeric(buildingmin_level)) as min_level, - nullif(material, '') AS material, - nullif(colour, '') AS colour, - FALSE as hide_3d - FROM - osm_building_relation WHERE building = '' AND ST_GeometryType(geometry) = 'ST_Polygon' - UNION ALL +CREATE OR REPLACE VIEW osm_all_buildings AS +( +SELECT + -- etldoc: osm_building_relation -> layer_building:z14_ + -- Buildings built from relations + member AS osm_id, + geometry, + COALESCE(CleanNumeric(height), CleanNumeric(buildingheight)) AS height, + COALESCE(CleanNumeric(min_height), CleanNumeric(buildingmin_height)) AS min_height, + COALESCE(CleanNumeric(levels), CleanNumeric(buildinglevels)) AS levels, + COALESCE(CleanNumeric(min_level), CleanNumeric(buildingmin_level)) AS min_level, + nullif(material, '') AS material, + nullif(colour, '') AS colour, + FALSE AS hide_3d +FROM osm_building_relation +WHERE building = '' + AND ST_GeometryType(geometry) = 'ST_Polygon' +UNION ALL - -- etldoc: osm_building_polygon -> layer_building:z14_ - -- Standalone buildings - SELECT obp.osm_id, obp.geometry, - COALESCE(CleanNumeric(obp.height), CleanNumeric(obp.buildingheight)) as height, - COALESCE(CleanNumeric(obp.min_height), CleanNumeric(obp.buildingmin_height)) as min_height, - COALESCE(CleanNumeric(obp.levels), CleanNumeric(obp.buildinglevels)) as levels, - COALESCE(CleanNumeric(obp.min_level), CleanNumeric(obp.buildingmin_level)) as min_level, - nullif(obp.material, '') AS material, - nullif(obp.colour, '') AS colour, - obr.role IS NOT NULL AS hide_3d - FROM - osm_building_polygon obp - LEFT JOIN osm_building_relation obr ON - obp.osm_id >= 0 AND - obr.member = obp.osm_id AND - obr.role = 'outline' - WHERE ST_GeometryType(obp.geometry) IN ('ST_Polygon', 'ST_MultiPolygon') -); +SELECT + -- etldoc: osm_building_polygon -> layer_building:z14_ + -- Standalone buildings + obp.osm_id, + obp.geometry, + COALESCE(CleanNumeric(obp.height), CleanNumeric(obp.buildingheight)) AS height, + COALESCE(CleanNumeric(obp.min_height), CleanNumeric(obp.buildingmin_height)) AS min_height, + COALESCE(CleanNumeric(obp.levels), CleanNumeric(obp.buildinglevels)) AS levels, + COALESCE(CleanNumeric(obp.min_level), CleanNumeric(obp.buildingmin_level)) AS min_level, + nullif(obp.material, '') AS material, + nullif(obp.colour, '') AS colour, + obr.role IS NOT NULL AS hide_3d +FROM osm_building_polygon obp + LEFT JOIN osm_building_relation obr ON + obp.osm_id >= 0 AND + obr.member = obp.osm_id AND + obr.role = 'outline' +WHERE ST_GeometryType(obp.geometry) IN ('ST_Polygon', 'ST_MultiPolygon') + ); CREATE OR REPLACE FUNCTION layer_building(bbox geometry, zoom_level int) -RETURNS TABLE(geometry geometry, osm_id bigint, render_height int, render_min_height int, colour text, hide_3d boolean) AS $$ - SELECT geometry, osm_id, render_height, render_min_height, + RETURNS TABLE + ( + geometry geometry, + osm_id bigint, + render_height int, + render_min_height int, + colour text, + hide_3d boolean + ) +AS +$$ +SELECT geometry, + osm_id, + render_height, + render_min_height, COALESCE(colour, CASE material -- Ordered by count from taginfo - WHEN 'cement_block' THEN '#6a7880' - WHEN 'brick' THEN '#bd8161' - WHEN 'plaster' THEN '#dadbdb' - WHEN 'wood' THEN '#d48741' - WHEN 'concrete' THEN '#d3c2b0' - WHEN 'metal' THEN '#b7b1a6' - WHEN 'stone' THEN '#b4a995' - WHEN 'mud' THEN '#9d8b75' - WHEN 'steel' THEN '#b7b1a6' -- same as metal - WHEN 'glass' THEN '#5a81a0' - WHEN 'traditional' THEN '#bd8161' -- same as brick - WHEN 'masonry' THEN '#bd8161' -- same as brick - WHEN 'Brick' THEN '#bd8161' -- same as brick - WHEN 'tin' THEN '#b7b1a6' -- same as metal - WHEN 'timber_framing' THEN '#b3b0a9' - WHEN 'sandstone' THEN '#b4a995' -- same as stone - WHEN 'clay' THEN '#9d8b75' -- same as mud - END) AS colour, - CASE WHEN hide_3d THEN TRUE END AS hide_3d - FROM ( - -- etldoc: osm_building_polygon_gen1 -> layer_building:z13 - SELECT - osm_id, geometry, - NULL::int AS render_height, NULL::int AS render_min_height, - NULL::text AS material, NULL::text AS colour, - FALSE AS hide_3d - FROM osm_building_polygon_gen1 - WHERE zoom_level = 13 AND geometry && bbox - UNION ALL - -- etldoc: osm_building_polygon -> layer_building:z14_ - SELECT DISTINCT ON (osm_id) - osm_id, geometry, - ceil(COALESCE(height, levels*3.66, 5))::int AS render_height, - floor(COALESCE(min_height, min_level*3.66, 0))::int AS render_min_height, - material, - colour, - hide_3d - FROM osm_all_buildings - WHERE - (levels IS NULL OR levels < 1000) AND - (min_level IS NULL OR min_level < 1000) AND - (height IS NULL OR height < 3000) AND - (min_height IS NULL OR min_height < 3000) AND - zoom_level >= 14 AND geometry && bbox - ) AS zoom_levels - ORDER BY render_height ASC, ST_YMin(geometry) DESC; -$$ -LANGUAGE SQL IMMUTABLE; + WHEN 'cement_block' THEN '#6a7880' + WHEN 'brick' THEN '#bd8161' + WHEN 'plaster' THEN '#dadbdb' + WHEN 'wood' THEN '#d48741' + WHEN 'concrete' THEN '#d3c2b0' + WHEN 'metal' THEN '#b7b1a6' + WHEN 'stone' THEN '#b4a995' + WHEN 'mud' THEN '#9d8b75' + WHEN 'steel' THEN '#b7b1a6' -- same as metal + WHEN 'glass' THEN '#5a81a0' + WHEN 'traditional' THEN '#bd8161' -- same as brick + WHEN 'masonry' THEN '#bd8161' -- same as brick + WHEN 'Brick' THEN '#bd8161' -- same as brick + WHEN 'tin' THEN '#b7b1a6' -- same as metal + WHEN 'timber_framing' THEN '#b3b0a9' + WHEN 'sandstone' THEN '#b4a995' -- same as stone + WHEN 'clay' THEN '#9d8b75' -- same as mud + END) AS colour, + CASE WHEN hide_3d THEN TRUE END AS hide_3d +FROM ( + SELECT + -- etldoc: osm_building_polygon_gen1 -> layer_building:z13 + osm_id, + geometry, + NULL::int AS render_height, + NULL::int AS render_min_height, + NULL::text AS material, + NULL::text AS colour, + FALSE AS hide_3d + FROM osm_building_polygon_gen1 + WHERE zoom_level = 13 + AND geometry && bbox + UNION ALL + SELECT + -- etldoc: osm_building_polygon -> layer_building:z14_ + DISTINCT ON (osm_id) osm_id, + geometry, + ceil(COALESCE(height, levels * 3.66, 5))::int AS render_height, + floor(COALESCE(min_height, min_level * 3.66, 0))::int AS render_min_height, + material, + colour, + hide_3d + FROM osm_all_buildings + WHERE (levels IS NULL OR levels < 1000) + AND (min_level IS NULL OR min_level < 1000) + AND (height IS NULL OR height < 3000) + AND (min_height IS NULL OR min_height < 3000) + AND zoom_level >= 14 + AND geometry && bbox + ) AS zoom_levels +ORDER BY render_height ASC, ST_YMin(geometry) DESC; +$$ LANGUAGE SQL IMMUTABLE; -- not handled: where a building outline covers building parts diff --git a/layers/housenumber/housenumber_centroid.sql b/layers/housenumber/housenumber_centroid.sql index a0722bd..fad1f3d 100644 --- a/layers/housenumber/housenumber_centroid.sql +++ b/layers/housenumber/housenumber_centroid.sql @@ -2,15 +2,17 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_housenumber_point; DROP TRIGGER IF EXISTS trigger_refresh ON housenumber.updates; -- etldoc: osm_housenumber_point -> osm_housenumber_point -CREATE OR REPLACE FUNCTION convert_housenumber_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION convert_housenumber_point() RETURNS void AS +$$ BEGIN - UPDATE osm_housenumber_point - SET geometry = - CASE WHEN ST_NPoints(ST_ConvexHull(geometry))=ST_NPoints(geometry) - THEN ST_Centroid(geometry) - ELSE ST_PointOnSurface(geometry) - END - WHERE ST_GeometryType(geometry) <> 'ST_Point'; + UPDATE osm_housenumber_point + SET geometry = + CASE + WHEN ST_NPoints(ST_ConvexHull(geometry)) = ST_NPoints(geometry) + THEN ST_Centroid(geometry) + ELSE ST_PointOnSurface(geometry) + END + WHERE ST_GeometryType(geometry) <> 'ST_Point'; END; $$ LANGUAGE plpgsql; @@ -20,32 +22,40 @@ SELECT convert_housenumber_point(); CREATE SCHEMA IF NOT EXISTS housenumber; -CREATE TABLE IF NOT EXISTS housenumber.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION housenumber.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS housenumber.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION housenumber.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO housenumber.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO housenumber.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION housenumber.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh housenumber'; PERFORM convert_housenumber_point(); + -- noinspection SqlWithoutWhere DELETE FROM housenumber.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_housenumber_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_housenumber_point FOR EACH STATEMENT - EXECUTE PROCEDURE housenumber.flag(); +EXECUTE PROCEDURE housenumber.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON housenumber.updates + AFTER INSERT + ON housenumber.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE housenumber.refresh(); +EXECUTE PROCEDURE housenumber.refresh(); diff --git a/layers/housenumber/layer.sql b/layers/housenumber/layer.sql index 01f2649..2cf0b55 100644 --- a/layers/housenumber/layer.sql +++ b/layers/housenumber/layer.sql @@ -1,12 +1,22 @@ - -- etldoc: layer_housenumber[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_housenumber | z14+" ] ; CREATE OR REPLACE FUNCTION layer_housenumber(bbox geometry, zoom_level integer) -RETURNS TABLE(osm_id bigint, geometry geometry, housenumber text) AS $$ - -- etldoc: osm_housenumber_point -> layer_housenumber:z14_ - SELECT osm_id, geometry, housenumber FROM osm_housenumber_point - WHERE zoom_level >= 14 AND geometry && bbox; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + housenumber text + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT + -- etldoc: osm_housenumber_point -> layer_housenumber:z14_ + osm_id, + geometry, + housenumber +FROM osm_housenumber_point +WHERE zoom_level >= 14 + AND geometry && bbox; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/landcover/landcover.sql b/layers/landcover/landcover.sql index 3fb62b6..e2e183f 100644 --- a/layers/landcover/landcover.sql +++ b/layers/landcover/landcover.sql @@ -9,127 +9,181 @@ --); --CREATE INDEX IF NOT EXISTS landcover_grouped_gen2_geometry_idx ON landcover_grouped_gen2 USING gist(geometry); -CREATE OR REPLACE FUNCTION landcover_class(subclass VARCHAR) RETURNS TEXT AS $$ - SELECT CASE - %%FIELD_MAPPING: class %% - END; +CREATE OR REPLACE FUNCTION landcover_class(subclass varchar) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT CASE + %%FIELD_MAPPING: class %% + END; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; -- etldoc: ne_110m_glaciated_areas -> landcover_z0 -CREATE OR REPLACE VIEW landcover_z0 AS ( - SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass FROM ne_110m_glaciated_areas -); +CREATE OR REPLACE VIEW landcover_z0 AS +( +SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass +FROM ne_110m_glaciated_areas + ); -CREATE OR REPLACE VIEW landcover_z2 AS ( - -- etldoc: ne_50m_glaciated_areas -> landcover_z2 - SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass FROM ne_50m_glaciated_areas - UNION ALL - -- etldoc: ne_50m_antarctic_ice_shelves_polys -> landcover_z2 - SELECT NULL::bigint AS osm_id, geometry, 'ice_shelf'::text AS subclass FROM ne_50m_antarctic_ice_shelves_polys -); +CREATE OR REPLACE VIEW landcover_z2 AS +( +-- etldoc: ne_50m_glaciated_areas -> landcover_z2 +SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass +FROM ne_50m_glaciated_areas +UNION ALL +-- etldoc: ne_50m_antarctic_ice_shelves_polys -> landcover_z2 +SELECT NULL::bigint AS osm_id, geometry, 'ice_shelf'::text AS subclass +FROM ne_50m_antarctic_ice_shelves_polys + ); -CREATE OR REPLACE VIEW landcover_z5 AS ( - -- etldoc: ne_10m_glaciated_areas -> landcover_z5 - SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass FROM ne_10m_glaciated_areas - UNION ALL - -- etldoc: ne_10m_antarctic_ice_shelves_polys -> landcover_z5 - SELECT NULL::bigint AS osm_id, geometry, 'ice_shelf'::text AS subclass FROM ne_10m_antarctic_ice_shelves_polys -); +CREATE OR REPLACE VIEW landcover_z5 AS +( +-- etldoc: ne_10m_glaciated_areas -> landcover_z5 +SELECT NULL::bigint AS osm_id, geometry, 'glacier'::text AS subclass +FROM ne_10m_glaciated_areas +UNION ALL +-- etldoc: ne_10m_antarctic_ice_shelves_polys -> landcover_z5 +SELECT NULL::bigint AS osm_id, geometry, 'ice_shelf'::text AS subclass +FROM ne_10m_antarctic_ice_shelves_polys + ); -CREATE OR REPLACE VIEW landcover_z7 AS ( - -- etldoc: osm_landcover_polygon_gen7 -> landcover_z7 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen7 -); +CREATE OR REPLACE VIEW landcover_z7 AS +( +-- etldoc: osm_landcover_polygon_gen7 -> landcover_z7 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen7 + ); -CREATE OR REPLACE VIEW landcover_z8 AS ( - -- etldoc: osm_landcover_polygon_gen6 -> landcover_z8 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen6 -); +CREATE OR REPLACE VIEW landcover_z8 AS +( +-- etldoc: osm_landcover_polygon_gen6 -> landcover_z8 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen6 + ); -CREATE OR REPLACE VIEW landcover_z9 AS ( - -- etldoc: osm_landcover_polygon_gen5 -> landcover_z9 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen5 -); +CREATE OR REPLACE VIEW landcover_z9 AS +( +-- etldoc: osm_landcover_polygon_gen5 -> landcover_z9 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen5 + ); -CREATE OR REPLACE VIEW landcover_z10 AS ( - -- etldoc: osm_landcover_polygon_gen4 -> landcover_z10 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen4 -); +CREATE OR REPLACE VIEW landcover_z10 AS +( +-- etldoc: osm_landcover_polygon_gen4 -> landcover_z10 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen4 + ); -CREATE OR REPLACE VIEW landcover_z11 AS ( - -- etldoc: osm_landcover_polygon_gen3 -> landcover_z11 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen3 -); +CREATE OR REPLACE VIEW landcover_z11 AS +( +-- etldoc: osm_landcover_polygon_gen3 -> landcover_z11 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen3 + ); -CREATE OR REPLACE VIEW landcover_z12 AS ( - -- etldoc: osm_landcover_polygon_gen2 -> landcover_z12 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen2 -); +CREATE OR REPLACE VIEW landcover_z12 AS +( +-- etldoc: osm_landcover_polygon_gen2 -> landcover_z12 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen2 + ); -CREATE OR REPLACE VIEW landcover_z13 AS ( - -- etldoc: osm_landcover_polygon_gen1 -> landcover_z13 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon_gen1 -); +CREATE OR REPLACE VIEW landcover_z13 AS +( +-- etldoc: osm_landcover_polygon_gen1 -> landcover_z13 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon_gen1 + ); -CREATE OR REPLACE VIEW landcover_z14 AS ( - -- etldoc: osm_landcover_polygon -> landcover_z14 - SELECT osm_id, geometry, subclass FROM osm_landcover_polygon -); +CREATE OR REPLACE VIEW landcover_z14 AS +( +-- etldoc: osm_landcover_polygon -> landcover_z14 +SELECT osm_id, geometry, subclass +FROM osm_landcover_polygon + ); -- etldoc: layer_landcover[shape=record fillcolor=lightpink, style="rounded, filled", label="layer_landcover | z0-z1 | z2-z4 | z5-z6 | z7 | z8 | z9 | z10 | z11 | z12| z13| z14+" ] ; CREATE OR REPLACE FUNCTION layer_landcover(bbox geometry, zoom_level int) -RETURNS TABLE(osm_id bigint, geometry geometry, class text, subclass text) AS $$ - SELECT osm_id, geometry, - landcover_class(subclass) AS class, - subclass - FROM ( - -- etldoc: landcover_z0 -> layer_landcover:z0_1 - SELECT * FROM landcover_z0 - WHERE zoom_level BETWEEN 0 AND 1 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z2 -> layer_landcover:z2_4 - SELECT * FROM landcover_z2 - WHERE zoom_level BETWEEN 2 AND 4 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z5 -> layer_landcover:z5_6 - SELECT * FROM landcover_z5 - WHERE zoom_level BETWEEN 5 AND 6 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z7 -> layer_landcover:z7 - SELECT * - FROM landcover_z7 WHERE zoom_level = 7 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z8 -> layer_landcover:z8 - SELECT * - FROM landcover_z8 WHERE zoom_level = 8 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z9 -> layer_landcover:z9 - SELECT * - FROM landcover_z9 WHERE zoom_level = 9 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z10 -> layer_landcover:z10 - SELECT * - FROM landcover_z10 WHERE zoom_level = 10 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z11 -> layer_landcover:z11 - SELECT * - FROM landcover_z11 WHERE zoom_level = 11 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z12 -> layer_landcover:z12 - SELECT * - FROM landcover_z12 WHERE zoom_level = 12 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z13 -> layer_landcover:z13 - SELECT * - FROM landcover_z13 WHERE zoom_level = 13 AND geometry && bbox - UNION ALL - -- etldoc: landcover_z14 -> layer_landcover:z14_ - SELECT * - FROM landcover_z14 WHERE zoom_level >= 14 AND geometry && bbox - ) AS zoom_levels; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + class text, + subclass text + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id, + geometry, + landcover_class(subclass) AS class, + subclass +FROM ( + -- etldoc: landcover_z0 -> layer_landcover:z0_1 + SELECT * + FROM landcover_z0 + WHERE zoom_level BETWEEN 0 AND 1 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z2 -> layer_landcover:z2_4 + SELECT * + FROM landcover_z2 + WHERE zoom_level BETWEEN 2 AND 4 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z5 -> layer_landcover:z5_6 + SELECT * + FROM landcover_z5 + WHERE zoom_level BETWEEN 5 AND 6 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z7 -> layer_landcover:z7 + SELECT * + FROM landcover_z7 + WHERE zoom_level = 7 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z8 -> layer_landcover:z8 + SELECT * + FROM landcover_z8 + WHERE zoom_level = 8 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z9 -> layer_landcover:z9 + SELECT * + FROM landcover_z9 + WHERE zoom_level = 9 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z10 -> layer_landcover:z10 + SELECT * + FROM landcover_z10 + WHERE zoom_level = 10 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z11 -> layer_landcover:z11 + SELECT * + FROM landcover_z11 + WHERE zoom_level = 11 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z12 -> layer_landcover:z12 + SELECT * + FROM landcover_z12 + WHERE zoom_level = 12 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z13 -> layer_landcover:z13 + SELECT * + FROM landcover_z13 + WHERE zoom_level = 13 + AND geometry && bbox + UNION ALL + -- etldoc: landcover_z14 -> layer_landcover:z14_ + SELECT * + FROM landcover_z14 + WHERE zoom_level >= 14 + AND geometry && bbox + ) AS zoom_levels; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/landuse/landuse.sql b/layers/landuse/landuse.sql index fb3f06a..89233ae 100644 --- a/layers/landuse/landuse.sql +++ b/layers/landuse/landuse.sql @@ -1,113 +1,218 @@ -- etldoc: ne_50m_urban_areas -> landuse_z4 -CREATE OR REPLACE VIEW landuse_z4 AS ( - SELECT NULL::bigint AS osm_id, geometry, 'residential'::text AS landuse, NULL::text AS amenity, NULL::text AS leisure, NULL::text AS tourism, NULL::text AS place, NULL::text AS waterway - FROM ne_50m_urban_areas - WHERE scalerank <= 2 -); +CREATE OR REPLACE VIEW landuse_z4 AS +( +SELECT NULL::bigint AS osm_id, + geometry, + 'residential'::text AS landuse, + NULL::text AS amenity, + NULL::text AS leisure, + NULL::text AS tourism, + NULL::text AS place, + NULL::text AS waterway +FROM ne_50m_urban_areas +WHERE scalerank <= 2 + ); -- etldoc: ne_50m_urban_areas -> landuse_z5 -CREATE OR REPLACE VIEW landuse_z5 AS ( - SELECT NULL::bigint AS osm_id, geometry, 'residential'::text AS landuse, NULL::text AS amenity, NULL::text AS leisure, NULL::text AS tourism, NULL::text AS place, NULL::text AS waterway - FROM ne_50m_urban_areas -); +CREATE OR REPLACE VIEW landuse_z5 AS +( +SELECT NULL::bigint AS osm_id, + geometry, + 'residential'::text AS landuse, + NULL::text AS amenity, + NULL::text AS leisure, + NULL::text AS tourism, + NULL::text AS place, + NULL::text AS waterway +FROM ne_50m_urban_areas + ); -- etldoc: osm_landuse_polygon_gen7 -> landuse_z6 -CREATE OR REPLACE VIEW landuse_z6 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen7 -); +CREATE OR REPLACE VIEW landuse_z6 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen7 + ); -- etldoc: osm_landuse_polygon_gen6 -> landuse_z8 -CREATE OR REPLACE VIEW landuse_z8 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen6 -); +CREATE OR REPLACE VIEW landuse_z8 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen6 + ); -- etldoc: osm_landuse_polygon_gen5 -> landuse_z9 -CREATE OR REPLACE VIEW landuse_z9 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen5 -); +CREATE OR REPLACE VIEW landuse_z9 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen5 + ); -- etldoc: osm_landuse_polygon_gen4 -> landuse_z10 -CREATE OR REPLACE VIEW landuse_z10 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen4 -); +CREATE OR REPLACE VIEW landuse_z10 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen4 + ); -- etldoc: osm_landuse_polygon_gen3 -> landuse_z11 -CREATE OR REPLACE VIEW landuse_z11 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen3 -); +CREATE OR REPLACE VIEW landuse_z11 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen3 + ); -- etldoc: osm_landuse_polygon_gen2 -> landuse_z12 -CREATE OR REPLACE VIEW landuse_z12 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen2 -); +CREATE OR REPLACE VIEW landuse_z12 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen2 + ); -- etldoc: osm_landuse_polygon_gen1 -> landuse_z13 -CREATE OR REPLACE VIEW landuse_z13 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon_gen1 -); +CREATE OR REPLACE VIEW landuse_z13 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon_gen1 + ); -- etldoc: osm_landuse_polygon -> landuse_z14 -CREATE OR REPLACE VIEW landuse_z14 AS ( - SELECT osm_id, geometry, landuse, amenity, leisure, tourism, place, waterway - FROM osm_landuse_polygon -); +CREATE OR REPLACE VIEW landuse_z14 AS +( +SELECT osm_id, + geometry, + landuse, + amenity, + leisure, + tourism, + place, + waterway +FROM osm_landuse_polygon + ); -- etldoc: layer_landuse[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_landuse | z4|z5|z6|z7| z8 | z9 | z10 | z11| z12| z13| z14+" ] ; CREATE OR REPLACE FUNCTION layer_landuse(bbox geometry, zoom_level int) -RETURNS TABLE(osm_id bigint, geometry geometry, class text) AS $$ - SELECT osm_id, geometry, - COALESCE( - NULLIF(landuse, ''), - NULLIF(amenity, ''), - NULLIF(leisure, ''), - NULLIF(tourism, ''), - NULLIF(place, ''), - NULLIF(waterway, '') - ) AS class - FROM ( - -- etldoc: landuse_z4 -> layer_landuse:z4 - SELECT * FROM landuse_z4 - WHERE zoom_level = 4 - UNION ALL - -- etldoc: landuse_z5 -> layer_landuse:z5 - SELECT * FROM landuse_z5 - WHERE zoom_level = 5 - UNION ALL - -- etldoc: landuse_z6 -> layer_landuse:z6 - -- etldoc: landuse_z6 -> layer_landuse:z7 - SELECT * FROM landuse_z6 WHERE zoom_level BETWEEN 6 AND 7 - UNION ALL - -- etldoc: landuse_z8 -> layer_landuse:z8 - SELECT * FROM landuse_z8 WHERE zoom_level = 8 - UNION ALL - -- etldoc: landuse_z9 -> layer_landuse:z9 - SELECT * FROM landuse_z9 WHERE zoom_level = 9 - UNION ALL - -- etldoc: landuse_z10 -> layer_landuse:z10 - SELECT * FROM landuse_z10 WHERE zoom_level = 10 - UNION ALL - -- etldoc: landuse_z11 -> layer_landuse:z11 - SELECT * FROM landuse_z11 WHERE zoom_level = 11 - UNION ALL - -- etldoc: landuse_z12 -> layer_landuse:z12 - SELECT * FROM landuse_z12 WHERE zoom_level = 12 - UNION ALL - -- etldoc: landuse_z13 -> layer_landuse:z13 - SELECT * FROM landuse_z13 WHERE zoom_level = 13 - UNION ALL - -- etldoc: landuse_z14 -> layer_landuse:z14 - SELECT * FROM landuse_z14 WHERE zoom_level >= 14 - ) AS zoom_levels - WHERE geometry && bbox; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + class text + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id, + geometry, + COALESCE( + NULLIF(landuse, ''), + NULLIF(amenity, ''), + NULLIF(leisure, ''), + NULLIF(tourism, ''), + NULLIF(place, ''), + NULLIF(waterway, '') + ) AS class +FROM ( + -- etldoc: landuse_z4 -> layer_landuse:z4 + SELECT * + FROM landuse_z4 + WHERE zoom_level = 4 + UNION ALL + -- etldoc: landuse_z5 -> layer_landuse:z5 + SELECT * + FROM landuse_z5 + WHERE zoom_level = 5 + UNION ALL + -- etldoc: landuse_z6 -> layer_landuse:z6 + -- etldoc: landuse_z6 -> layer_landuse:z7 + SELECT * + FROM landuse_z6 + WHERE zoom_level BETWEEN 6 AND 7 + UNION ALL + -- etldoc: landuse_z8 -> layer_landuse:z8 + SELECT * + FROM landuse_z8 + WHERE zoom_level = 8 + UNION ALL + -- etldoc: landuse_z9 -> layer_landuse:z9 + SELECT * + FROM landuse_z9 + WHERE zoom_level = 9 + UNION ALL + -- etldoc: landuse_z10 -> layer_landuse:z10 + SELECT * + FROM landuse_z10 + WHERE zoom_level = 10 + UNION ALL + -- etldoc: landuse_z11 -> layer_landuse:z11 + SELECT * + FROM landuse_z11 + WHERE zoom_level = 11 + UNION ALL + -- etldoc: landuse_z12 -> layer_landuse:z12 + SELECT * + FROM landuse_z12 + WHERE zoom_level = 12 + UNION ALL + -- etldoc: landuse_z13 -> layer_landuse:z13 + SELECT * + FROM landuse_z13 + WHERE zoom_level = 13 + UNION ALL + -- etldoc: landuse_z14 -> layer_landuse:z14 + SELECT * + FROM landuse_z14 + WHERE zoom_level >= 14 + ) AS zoom_levels +WHERE geometry && bbox; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/mountain_peak/layer.sql b/layers/mountain_peak/layer.sql index 2fb8fa9..a104fac 100644 --- a/layers/mountain_peak/layer.sql +++ b/layers/mountain_peak/layer.sql @@ -1,57 +1,61 @@ - -- etldoc: layer_mountain_peak[shape=record fillcolor=lightpink, -- etldoc: style="rounded,filled", label="layer_mountain_peak | z7+" ] ; -CREATE OR REPLACE FUNCTION layer_mountain_peak( - bbox geometry, - zoom_level integer, - pixel_width numeric) - RETURNS TABLE( - osm_id bigint, - geometry geometry, - name text, - name_en text, - name_de text, - class text, - tags hstore, - ele int, - ele_ft int, - "rank" int) AS +CREATE OR REPLACE FUNCTION layer_mountain_peak(bbox geometry, + zoom_level integer, + pixel_width numeric) + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + class text, + tags hstore, + ele int, + ele_ft int, + "rank" int + ) +AS $$ - -- etldoc: osm_peak_point -> layer_mountain_peak:z7_ - SELECT +SELECT + -- etldoc: osm_peak_point -> layer_mountain_peak:z7_ osm_id, geometry, name, name_en, name_de, - tags -> 'natural' AS class, + tags->'natural' AS class, tags, ele::int, ele_ft::int, - rank::int FROM ( - SELECT osm_id, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - substring(ele from E'^(-?\\d+)(\\D|$)')::int AS ele, - round(substring(ele from E'^(-?\\d+)(\\D|$)')::int*3.2808399)::int AS ele_ft, - row_number() OVER ( - PARTITION BY LabelGrid(geometry, 100 * pixel_width) - ORDER BY ( - substring(ele from E'^(-?\\d+)(\\D|$)')::int + - (CASE WHEN NULLIF(wikipedia, '') is not null THEN 10000 ELSE 0 END) + - (CASE WHEN NULLIF(name, '') is not null THEN 10000 ELSE 0 END) - ) DESC - )::int AS "rank" - FROM osm_peak_point - WHERE geometry && bbox - AND ele is not null - AND ele ~ E'^-?\\d{1,4}(\\D|$)' - ) AS ranked_peaks - WHERE zoom_level >= 7 AND (rank <= 5 OR zoom_level >= 14) - ORDER BY "rank" ASC; + rank::int +FROM ( + SELECT osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + substring(ele FROM E'^(-?\\d+)(\\D|$)')::int AS ele, + round(substring(ele FROM E'^(-?\\d+)(\\D|$)')::int * 3.2808399)::int AS ele_ft, + row_number() OVER ( + PARTITION BY LabelGrid(geometry, 100 * pixel_width) + ORDER BY ( + substring(ele FROM E'^(-?\\d+)(\\D|$)')::int + + (CASE WHEN NULLIF(wikipedia, '') IS NOT NULL THEN 10000 ELSE 0 END) + + (CASE WHEN NULLIF(name, '') IS NOT NULL THEN 10000 ELSE 0 END) + ) DESC + )::int AS "rank" + FROM osm_peak_point + WHERE geometry && bbox + AND ele IS NOT NULL + AND ele ~ E'^-?\\d{1,4}(\\D|$)' + ) AS ranked_peaks +WHERE zoom_level >= 7 + AND (rank <= 5 OR zoom_level >= 14) +ORDER BY "rank" ASC; -$$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/mountain_peak/update_peak_point.sql b/layers/mountain_peak/update_peak_point.sql index 666bf97..8a08ba6 100644 --- a/layers/mountain_peak/update_peak_point.sql +++ b/layers/mountain_peak/update_peak_point.sql @@ -2,11 +2,12 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_peak_point; DROP TRIGGER IF EXISTS trigger_refresh ON mountain_peak_point.updates; -- etldoc: osm_peak_point -> osm_peak_point -CREATE OR REPLACE FUNCTION update_osm_peak_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_peak_point() RETURNS void AS +$$ BEGIN - UPDATE osm_peak_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_peak_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -17,32 +18,40 @@ SELECT update_osm_peak_point(); CREATE SCHEMA IF NOT EXISTS mountain_peak_point; -CREATE TABLE IF NOT EXISTS mountain_peak_point.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION mountain_peak_point.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS mountain_peak_point.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION mountain_peak_point.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO mountain_peak_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO mountain_peak_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION mountain_peak_point.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh mountain_peak_point'; PERFORM update_osm_peak_point(); + -- noinspection SqlWithoutWhere DELETE FROM mountain_peak_point.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_peak_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_peak_point FOR EACH STATEMENT - EXECUTE PROCEDURE mountain_peak_point.flag(); +EXECUTE PROCEDURE mountain_peak_point.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON mountain_peak_point.updates + AFTER INSERT + ON mountain_peak_point.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE mountain_peak_point.refresh(); +EXECUTE PROCEDURE mountain_peak_point.refresh(); diff --git a/layers/park/layer.sql b/layers/park/layer.sql index bb8162a..71157b9 100644 --- a/layers/park/layer.sql +++ b/layers/park/layer.sql @@ -2,134 +2,331 @@ -- etldoc: label="layer_park | z6 | z7 | z8 | z9 | z10 | z11 | z12| z13| z14+" ] ; CREATE OR REPLACE FUNCTION layer_park(bbox geometry, zoom_level int, pixel_width numeric) -RETURNS TABLE(osm_id bigint, geometry geometry, class text, name text, name_en text, name_de text, tags hstore, rank int) AS $$ - SELECT osm_id, geometry, class, name, name_en, name_de, tags, rank - FROM ( - SELECT osm_id, geometry, - COALESCE( - LOWER(REPLACE(NULLIF(protection_title, ''), ' ', '_')), - NULLIF(boundary, ''), - NULLIF(leisure, '') - ) AS class, - name, name_en, name_de, tags, - NULL::int as rank - FROM ( - -- etldoc: osm_park_polygon_gen8 -> layer_park:z6 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen8 - WHERE zoom_level = 6 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen7 -> layer_park:z7 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen7 - WHERE zoom_level = 7 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen6 -> layer_park:z8 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen6 - WHERE zoom_level = 8 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen5 -> layer_park:z9 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen5 - WHERE zoom_level = 9 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen4 -> layer_park:z10 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen4 - WHERE zoom_level = 10 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen3 -> layer_park:z11 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen3 - WHERE zoom_level = 11 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen2 -> layer_park:z12 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen2 - WHERE zoom_level = 12 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon_gen1 -> layer_park:z13 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon_gen1 - WHERE zoom_level = 13 AND geometry && bbox - UNION ALL - -- etldoc: osm_park_polygon -> layer_park:z14 - SELECT osm_id, geometry, name, name_en, name_de, tags, leisure, boundary, protection_title - FROM osm_park_polygon - WHERE zoom_level >= 14 AND geometry && bbox - ) AS park_polygon - - UNION ALL - SELECT osm_id, geometry_point AS geometry, - COALESCE( - LOWER(REPLACE(NULLIF(protection_title, ''), ' ', '_')), - NULLIF(boundary, ''), - NULLIF(leisure, '') - ) AS class, - name, name_en, name_de, tags, - row_number() OVER ( - PARTITION BY LabelGrid(geometry_point, 100 * pixel_width) - ORDER BY - (CASE WHEN boundary = 'national_park' THEN true ELSE false END) DESC, - (COALESCE(NULLIF(tags->'wikipedia', ''), NULLIF(tags->'wikidata', '')) IS NOT NULL) DESC, - area DESC - )::int AS "rank" - FROM ( - -- etldoc: osm_park_polygon_gen8 -> layer_park:z6 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen8 - WHERE zoom_level = 6 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen7 -> layer_park:z7 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen7 - WHERE zoom_level = 7 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen6 -> layer_park:z8 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen6 - WHERE zoom_level = 8 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen5 -> layer_park:z9 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen5 - WHERE zoom_level = 9 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen4 -> layer_park:z10 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen4 - WHERE zoom_level = 10 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen3 -> layer_park:z11 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen3 - WHERE zoom_level = 11 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen2 -> layer_park:z12 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen2 - WHERE zoom_level = 12 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon_gen1 -> layer_park:z13 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon_gen1 - WHERE zoom_level = 13 AND geometry_point && bbox - UNION ALL - - -- etldoc: osm_park_polygon -> layer_park:z14 - SELECT osm_id, geometry_point, name, name_en, name_de, tags, leisure, boundary, protection_title, area - FROM osm_park_polygon - WHERE zoom_level >= 14 AND geometry_point && bbox - ) AS park_point - ) AS park_all; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + class text, + name text, + name_en text, + name_de text, + tags hstore, + rank int + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id, + geometry, + class, + name, + name_en, + name_de, + tags, + rank +FROM ( + SELECT osm_id, + geometry, + COALESCE( + LOWER(REPLACE(NULLIF(protection_title, ''), ' ', '_')), + NULLIF(boundary, ''), + NULLIF(leisure, '') + ) AS class, + name, + name_en, + name_de, + tags, + NULL::int AS rank + FROM ( + -- etldoc: osm_park_polygon_gen8 -> layer_park:z6 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen8 + WHERE zoom_level = 6 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen7 -> layer_park:z7 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen7 + WHERE zoom_level = 7 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen6 -> layer_park:z8 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen6 + WHERE zoom_level = 8 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen5 -> layer_park:z9 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen5 + WHERE zoom_level = 9 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen4 -> layer_park:z10 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen4 + WHERE zoom_level = 10 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen3 -> layer_park:z11 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen3 + WHERE zoom_level = 11 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen2 -> layer_park:z12 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen2 + WHERE zoom_level = 12 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon_gen1 -> layer_park:z13 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon_gen1 + WHERE zoom_level = 13 + AND geometry && bbox + UNION ALL + -- etldoc: osm_park_polygon -> layer_park:z14 + SELECT osm_id, + geometry, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title + FROM osm_park_polygon + WHERE zoom_level >= 14 + AND geometry && bbox + ) AS park_polygon + + UNION ALL + SELECT osm_id, + geometry_point AS geometry, + COALESCE( + LOWER(REPLACE(NULLIF(protection_title, ''), ' ', '_')), + NULLIF(boundary, ''), + NULLIF(leisure, '') + ) AS class, + name, + name_en, + name_de, + tags, + row_number() OVER ( + PARTITION BY LabelGrid(geometry_point, 100 * pixel_width) + ORDER BY + (CASE WHEN boundary = 'national_park' THEN TRUE ELSE FALSE END) DESC, + (COALESCE(NULLIF(tags->'wikipedia', ''), NULLIF(tags->'wikidata', '')) IS NOT NULL) DESC, + area DESC + )::int AS "rank" + FROM ( + -- etldoc: osm_park_polygon_gen8 -> layer_park:z6 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen8 + WHERE zoom_level = 6 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen7 -> layer_park:z7 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen7 + WHERE zoom_level = 7 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen6 -> layer_park:z8 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen6 + WHERE zoom_level = 8 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen5 -> layer_park:z9 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen5 + WHERE zoom_level = 9 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen4 -> layer_park:z10 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen4 + WHERE zoom_level = 10 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen3 -> layer_park:z11 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen3 + WHERE zoom_level = 11 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen2 -> layer_park:z12 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen2 + WHERE zoom_level = 12 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon_gen1 -> layer_park:z13 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon_gen1 + WHERE zoom_level = 13 + AND geometry_point && bbox + UNION ALL + + -- etldoc: osm_park_polygon -> layer_park:z14 + SELECT osm_id, + geometry_point, + name, + name_en, + name_de, + tags, + leisure, + boundary, + protection_title, + area + FROM osm_park_polygon + WHERE zoom_level >= 14 + AND geometry_point && bbox + ) AS park_point + ) AS park_all; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/park/update_park_polygon.sql b/layers/park/update_park_polygon.sql index 1dabc00..23fe2f6 100644 --- a/layers/park/update_park_polygon.sql +++ b/layers/park/update_park_polygon.sql @@ -1,12 +1,22 @@ -ALTER TABLE osm_park_polygon ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen1 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen2 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen3 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen4 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen5 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen6 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen7 ADD COLUMN IF NOT EXISTS geometry_point geometry; -ALTER TABLE osm_park_polygon_gen8 ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen1 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen2 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen3 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen4 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen5 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen6 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen7 + ADD COLUMN IF NOT EXISTS geometry_point geometry; +ALTER TABLE osm_park_polygon_gen8 + ADD COLUMN IF NOT EXISTS geometry_point geometry; + DROP TRIGGER IF EXISTS update_row ON osm_park_polygon; DROP TRIGGER IF EXISTS update_row ON osm_park_polygon_gen1; DROP TRIGGER IF EXISTS update_row ON osm_park_polygon_gen2; @@ -26,115 +36,121 @@ DROP TRIGGER IF EXISTS update_row ON osm_park_polygon_gen8; -- etldoc: osm_park_polygon_gen6 -> osm_park_polygon_gen6 -- etldoc: osm_park_polygon_gen7 -> osm_park_polygon_gen7 -- etldoc: osm_park_polygon_gen8 -> osm_park_polygon_gen8 -CREATE OR REPLACE FUNCTION update_osm_park_polygon() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_park_polygon() RETURNS void AS +$$ BEGIN - UPDATE osm_park_polygon - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen1 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen1 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen2 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen2 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen3 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen3 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen4 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen4 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen5 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen5 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen6 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen6 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen7 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen7 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); - UPDATE osm_park_polygon_gen8 - SET tags = update_tags(tags, geometry), - geometry_point = st_centroid(geometry); + UPDATE osm_park_polygon_gen8 + SET tags = update_tags(tags, geometry), + geometry_point = st_centroid(geometry); END; $$ LANGUAGE plpgsql; SELECT update_osm_park_polygon(); -CREATE INDEX IF NOT EXISTS osm_park_polygon_point_geom_idx ON osm_park_polygon USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen1_point_geom_idx ON osm_park_polygon_gen1 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen2_point_geom_idx ON osm_park_polygon_gen2 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen3_point_geom_idx ON osm_park_polygon_gen3 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen4_point_geom_idx ON osm_park_polygon_gen4 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen5_point_geom_idx ON osm_park_polygon_gen5 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen6_point_geom_idx ON osm_park_polygon_gen6 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen7_point_geom_idx ON osm_park_polygon_gen7 USING gist(geometry_point); -CREATE INDEX IF NOT EXISTS osm_park_polygon_gen8_point_geom_idx ON osm_park_polygon_gen8 USING gist(geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_point_geom_idx ON osm_park_polygon USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen1_point_geom_idx ON osm_park_polygon_gen1 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen2_point_geom_idx ON osm_park_polygon_gen2 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen3_point_geom_idx ON osm_park_polygon_gen3 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen4_point_geom_idx ON osm_park_polygon_gen4 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen5_point_geom_idx ON osm_park_polygon_gen5 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen6_point_geom_idx ON osm_park_polygon_gen6 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen7_point_geom_idx ON osm_park_polygon_gen7 USING gist (geometry_point); +CREATE INDEX IF NOT EXISTS osm_park_polygon_gen8_point_geom_idx ON osm_park_polygon_gen8 USING gist (geometry_point); CREATE OR REPLACE FUNCTION update_osm_park_polygon_row() - RETURNS TRIGGER + RETURNS trigger AS -$BODY$ +$$ BEGIN - NEW.tags = update_tags(NEW.tags, NEW.geometry); - NEW.geometry_point = st_centroid(NEW.geometry); - RETURN NEW; + NEW.tags = update_tags(NEW.tags, NEW.geometry); + NEW.geometry_point = st_centroid(NEW.geometry); + RETURN NEW; END; -$BODY$ -LANGUAGE plpgsql; +$$ LANGUAGE plpgsql; CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen1 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen1 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen2 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen2 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen3 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen3 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen4 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen4 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen5 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen5 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen6 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen6 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen7 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen7 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); CREATE TRIGGER update_row -BEFORE INSERT OR UPDATE ON osm_park_polygon_gen8 -FOR EACH ROW + BEFORE INSERT OR UPDATE + ON osm_park_polygon_gen8 + FOR EACH ROW EXECUTE PROCEDURE update_osm_park_polygon_row(); - - - diff --git a/layers/place/capital.sql b/layers/place/capital.sql index 434d3fb..3375647 100644 --- a/layers/place/capital.sql +++ b/layers/place/capital.sql @@ -1,9 +1,10 @@ -CREATE OR REPLACE FUNCTION normalize_capital_level(capital TEXT) -RETURNS INT AS $$ - SELECT CASE - WHEN capital IN ('yes', '2') THEN 2 - WHEN capital = '4' THEN 4 - END; +CREATE OR REPLACE FUNCTION normalize_capital_level(capital text) + RETURNS int AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN capital IN ('yes', '2') THEN 2 + WHEN capital = '4' THEN 4 + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; diff --git a/layers/place/city.sql b/layers/place/city.sql index e3ef2d6..4cc0b84 100644 --- a/layers/place/city.sql +++ b/layers/place/city.sql @@ -1,57 +1,78 @@ - -- etldoc: layer_city[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_city | z2-z14+" ] ; -- etldoc: osm_city_point -> layer_city:z2_14 CREATE OR REPLACE FUNCTION layer_city(bbox geometry, zoom_level int, pixel_width numeric) -RETURNS TABLE(osm_id bigint, geometry geometry, name text, name_en text, name_de text, tags hstore, place city_place, "rank" int, capital int) AS $$ - SELECT * FROM ( - SELECT osm_id, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - place, "rank", normalize_capital_level(capital) AS capital - FROM osm_city_point - WHERE geometry && bbox - AND ((zoom_level = 2 AND "rank" = 1) - OR (zoom_level BETWEEN 3 AND 7 AND "rank" <= zoom_level + 1) - ) - UNION ALL - SELECT osm_id, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - place, - COALESCE("rank", gridrank + 10), - normalize_capital_level(capital) AS capital - FROM ( - SELECT osm_id, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - place, "rank", capital, - row_number() OVER ( - PARTITION BY LabelGrid(geometry, 128 * pixel_width) - ORDER BY "rank" ASC NULLS LAST, - place ASC NULLS LAST, - population DESC NULLS LAST, - length(name) ASC - )::int AS gridrank - FROM osm_city_point - WHERE geometry && bbox - AND ((zoom_level = 7 AND place <= 'town'::city_place - OR (zoom_level BETWEEN 8 AND 10 AND place <= 'village'::city_place) - - OR (zoom_level BETWEEN 11 AND 13 AND place <= 'suburb'::city_place) - OR (zoom_level >= 14) - )) - ) AS ranked_places - WHERE (zoom_level BETWEEN 7 AND 8 AND (gridrank <= 4 OR "rank" IS NOT NULL)) - OR (zoom_level = 9 AND (gridrank <= 8 OR "rank" IS NOT NULL)) - OR (zoom_level = 10 AND (gridrank <= 12 OR "rank" IS NOT NULL)) - OR (zoom_level BETWEEN 11 AND 12 AND (gridrank <= 14 OR "rank" IS NOT NULL)) - OR (zoom_level >= 13) - ) as city_all; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + place city_place, + "rank" int, + capital int + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT * +FROM ( + SELECT osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + place, + "rank", + normalize_capital_level(capital) AS capital + FROM osm_city_point + WHERE geometry && bbox + AND ((zoom_level = 2 AND "rank" = 1) + OR (zoom_level BETWEEN 3 AND 7 AND "rank" <= zoom_level + 1) + ) + UNION ALL + SELECT osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + place, + COALESCE("rank", gridrank + 10), + normalize_capital_level(capital) AS capital + FROM ( + SELECT osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + place, + "rank", + capital, + row_number() OVER ( + PARTITION BY LabelGrid(geometry, 128 * pixel_width) + ORDER BY "rank" ASC NULLS LAST, + place ASC NULLS LAST, + population DESC NULLS LAST, + length(name) ASC + )::int AS gridrank + FROM osm_city_point + WHERE geometry && bbox + AND ((zoom_level = 7 AND place <= 'town'::city_place + OR (zoom_level BETWEEN 8 AND 10 AND place <= 'village'::city_place) + OR (zoom_level BETWEEN 11 AND 13 AND place <= 'suburb'::city_place) + OR (zoom_level >= 14) + )) + ) AS ranked_places + WHERE (zoom_level BETWEEN 7 AND 8 AND (gridrank <= 4 OR "rank" IS NOT NULL)) + OR (zoom_level = 9 AND (gridrank <= 8 OR "rank" IS NOT NULL)) + OR (zoom_level = 10 AND (gridrank <= 12 OR "rank" IS NOT NULL)) + OR (zoom_level BETWEEN 11 AND 12 AND (gridrank <= 14 OR "rank" IS NOT NULL)) + OR (zoom_level >= 13) + ) AS city_all; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/place/island_rank.sql b/layers/place/island_rank.sql index 15b8d5a..f7ef3ef 100644 --- a/layers/place/island_rank.sql +++ b/layers/place/island_rank.sql @@ -1,11 +1,12 @@ -CREATE OR REPLACE FUNCTION island_rank(area REAL) RETURNS INT AS $$ - SELECT CASE - WHEN area < 10000000 THEN 6 - WHEN area BETWEEN 1000000 AND 15000000 THEN 5 - WHEN area BETWEEN 15000000 AND 40000000 THEN 4 - WHEN area > 40000000 THEN 3 - ELSE 7 - END; +CREATE OR REPLACE FUNCTION island_rank(area real) RETURNS int AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN area < 10000000 THEN 6 + WHEN area BETWEEN 1000000 AND 15000000 THEN 5 + WHEN area BETWEEN 15000000 AND 40000000 THEN 4 + WHEN area > 40000000 THEN 3 + ELSE 7 + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; diff --git a/layers/place/layer.sql b/layers/place/layer.sql index f4d3d40..0dee27d 100644 --- a/layers/place/layer.sql +++ b/layers/place/layer.sql @@ -1,101 +1,146 @@ - -- etldoc: layer_place[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_place | z0-3| z4-7| z8-11| z12-z14+" ] ; CREATE OR REPLACE FUNCTION layer_place(bbox geometry, zoom_level int, pixel_width numeric) -RETURNS TABLE(osm_id bigint, geometry geometry, name text, name_en text, - name_de text, tags hstore, class text, "rank" int, capital INT, iso_a2 - TEXT) AS $$ - SELECT * FROM ( - - -- etldoc: osm_continent_point -> layer_place:z0_3 - SELECT - osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - 'continent' AS class, 1 AS "rank", NULL::int AS capital, - NULL::text AS iso_a2 - FROM osm_continent_point - WHERE geometry && bbox AND zoom_level < 4 - UNION ALL - - -- etldoc: osm_country_point -> layer_place:z0_3 - -- etldoc: osm_country_point -> layer_place:z4_7 - -- etldoc: osm_country_point -> layer_place:z8_11 - -- etldoc: osm_country_point -> layer_place:z12_14 - SELECT - osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - 'country' AS class, "rank", NULL::int AS capital, - iso3166_1_alpha_2 AS iso_a2 - FROM osm_country_point - WHERE geometry && bbox AND "rank" <= zoom_level + 1 AND name <> '' - UNION ALL - - -- etldoc: osm_state_point -> layer_place:z0_3 - -- etldoc: osm_state_point -> layer_place:z4_7 - -- etldoc: osm_state_point -> layer_place:z8_11 - -- etldoc: osm_state_point -> layer_place:z12_14 - SELECT - osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - 'state' AS class, "rank", NULL::int AS capital, - NULL::text AS iso_a2 - FROM osm_state_point - WHERE geometry && bbox AND - name <> '' AND - ("rank" + 2 <= zoom_level) AND ( - zoom_level >= 5 OR - is_in_country IN ('United Kingdom', 'USA', 'Россия', 'Brasil', 'China', 'India') OR - is_in_country_code IN ('AU', 'CN', 'IN', 'BR', 'US')) - UNION ALL - - -- etldoc: osm_island_point -> layer_place:z12_14 - SELECT - osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - 'island' AS class, 7 AS "rank", NULL::int AS capital, - NULL::text AS iso_a2 - FROM osm_island_point - WHERE zoom_level >= 12 - AND geometry && bbox - UNION ALL - - -- etldoc: osm_island_polygon -> layer_place:z8_11 - -- etldoc: osm_island_polygon -> layer_place:z12_14 - SELECT - osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - 'island' AS class, island_rank(area) AS "rank", NULL::int AS capital, - NULL::text AS iso_a2 - FROM osm_island_polygon - WHERE geometry && bbox AND - ((zoom_level = 8 AND island_rank(area) <= 3) - OR (zoom_level = 9 AND island_rank(area) <= 4) - OR (zoom_level >= 10)) - UNION ALL - - -- etldoc: layer_city -> layer_place:z0_3 - -- etldoc: layer_city -> layer_place:z4_7 - -- etldoc: layer_city -> layer_place:z8_11 - -- etldoc: layer_city -> layer_place:z12_14 - SELECT - osm_id*10, geometry, name, name_en, name_de, - tags, - place::text AS class, "rank", capital, - NULL::text AS iso_a2 - FROM layer_city(bbox, zoom_level, pixel_width) - ORDER BY "rank" ASC - ) AS place_all + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + class text, + "rank" int, + capital int, + iso_a2 text + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT * +FROM ( + SELECT + -- etldoc: osm_continent_point -> layer_place:z0_3 + osm_id * 10 AS osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + 'continent' AS class, + 1 AS "rank", + NULL::int AS capital, + NULL::text AS iso_a2 + FROM osm_continent_point + WHERE geometry && bbox + AND zoom_level < 4 + + UNION ALL + + SELECT + -- etldoc: osm_country_point -> layer_place:z0_3 + -- etldoc: osm_country_point -> layer_place:z4_7 + -- etldoc: osm_country_point -> layer_place:z8_11 + -- etldoc: osm_country_point -> layer_place:z12_14 + osm_id * 10 AS osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + 'country' AS class, + "rank", + NULL::int AS capital, + iso3166_1_alpha_2 AS iso_a2 + FROM osm_country_point + WHERE geometry && bbox + AND "rank" <= zoom_level + 1 + AND name <> '' + + UNION ALL + + SELECT + -- etldoc: osm_state_point -> layer_place:z0_3 + -- etldoc: osm_state_point -> layer_place:z4_7 + -- etldoc: osm_state_point -> layer_place:z8_11 + -- etldoc: osm_state_point -> layer_place:z12_14 + osm_id * 10 AS osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + 'state' AS class, + "rank", + NULL::int AS capital, + NULL::text AS iso_a2 + FROM osm_state_point + WHERE geometry && bbox + AND name <> '' + AND ("rank" + 2 <= zoom_level) + AND ( + zoom_level >= 5 OR + is_in_country IN ('United Kingdom', 'USA', 'Россия', 'Brasil', 'China', 'India') OR + is_in_country_code IN ('AU', 'CN', 'IN', 'BR', 'US')) + + UNION ALL + + SELECT + -- etldoc: osm_island_point -> layer_place:z12_14 + osm_id * 10 AS osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + 'island' AS class, + 7 AS "rank", + NULL::int AS capital, + NULL::text AS iso_a2 + FROM osm_island_point + WHERE zoom_level >= 12 + AND geometry && bbox + + UNION ALL + + SELECT + -- etldoc: osm_island_polygon -> layer_place:z8_11 + -- etldoc: osm_island_polygon -> layer_place:z12_14 + osm_id * 10 AS osm_id, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + 'island' AS class, + island_rank(area) AS "rank", + NULL::int AS capital, + NULL::text AS iso_a2 + FROM osm_island_polygon + WHERE geometry && bbox + AND ((zoom_level = 8 AND island_rank(area) <= 3) + OR (zoom_level = 9 AND island_rank(area) <= 4) + OR (zoom_level >= 10)) + + UNION ALL + + SELECT + -- etldoc: layer_city -> layer_place:z0_3 + -- etldoc: layer_city -> layer_place:z4_7 + -- etldoc: layer_city -> layer_place:z8_11 + -- etldoc: layer_city -> layer_place:z12_14 + osm_id * 10 AS osm_id, + geometry, + name, + name_en, + name_de, + tags, + place::text AS class, + "rank", + capital, + NULL::text AS iso_a2 + FROM layer_city(bbox, zoom_level, pixel_width) + ORDER BY "rank" ASC + ) AS place_all +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/place/types.sql b/layers/place/types.sql index f7fdedf..1ecdd3b 100644 --- a/layers/place/types.sql +++ b/layers/place/types.sql @@ -1,9 +1,11 @@ -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'city_place') THEN - CREATE TYPE city_place AS ENUM ('city', 'town', 'village', 'hamlet', 'suburb', 'neighbourhood', 'isolated_dwelling'); - END IF; -END +DO +$$ + BEGIN + IF NOT EXISTS(SELECT 1 FROM pg_type WHERE typname = 'city_place') THEN + CREATE TYPE city_place AS enum ('city', 'town', 'village', 'hamlet', 'suburb', 'neighbourhood', 'isolated_dwelling'); + END IF; + END $$; -ALTER TABLE osm_city_point ALTER COLUMN place TYPE city_place USING place::city_place; +ALTER TABLE osm_city_point + ALTER COLUMN place TYPE city_place USING place::city_place; diff --git a/layers/place/update_city_point.sql b/layers/place/update_city_point.sql index 1dae791..7766491 100644 --- a/layers/place/update_city_point.sql +++ b/layers/place/update_city_point.sql @@ -3,85 +3,94 @@ DROP TRIGGER IF EXISTS trigger_refresh ON place_city.updates; CREATE EXTENSION IF NOT EXISTS unaccent; -CREATE OR REPLACE FUNCTION update_osm_city_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_city_point() RETURNS void AS +$$ BEGIN - -- Clear OSM key:rank ( https://github.com/openmaptiles/openmaptiles/issues/108 ) - -- etldoc: osm_city_point -> osm_city_point - UPDATE osm_city_point AS osm SET "rank" = NULL WHERE "rank" IS NOT NULL; + -- Clear OSM key:rank ( https://github.com/openmaptiles/openmaptiles/issues/108 ) + -- etldoc: osm_city_point -> osm_city_point + UPDATE osm_city_point AS osm SET "rank" = NULL WHERE "rank" IS NOT NULL; - -- etldoc: ne_10m_populated_places -> osm_city_point - -- etldoc: osm_city_point -> osm_city_point + -- etldoc: ne_10m_populated_places -> osm_city_point + -- etldoc: osm_city_point -> osm_city_point - WITH important_city_point AS ( - SELECT osm.geometry, osm.osm_id, osm.name, osm.name_en, ne.scalerank, ne.labelrank - FROM ne_10m_populated_places AS ne, osm_city_point AS osm - WHERE - ( - (osm.tags ? 'wikidata' AND osm.tags->'wikidata' = ne.wikidataid) OR - ne.name ILIKE osm.name OR - ne.name ILIKE osm.name_en OR - ne.namealt ILIKE osm.name OR - ne.namealt ILIKE osm.name_en OR - ne.meganame ILIKE osm.name OR - ne.meganame ILIKE osm.name_en OR - ne.gn_ascii ILIKE osm.name OR - ne.gn_ascii ILIKE osm.name_en OR - ne.nameascii ILIKE osm.name OR - ne.nameascii ILIKE osm.name_en OR - ne.name = unaccent(osm.name) - ) - AND osm.place IN ('city', 'town', 'village') - AND ST_DWithin(ne.geometry, osm.geometry, 50000) - ) - UPDATE osm_city_point AS osm - -- Move scalerank to range 1 to 10 and merge scalerank 5 with 6 since not enough cities - -- are in the scalerank 5 bucket - SET "rank" = CASE WHEN scalerank <= 5 THEN scalerank + 1 ELSE scalerank END - FROM important_city_point AS ne - WHERE osm.osm_id = ne.osm_id; + WITH important_city_point AS ( + SELECT osm.geometry, osm.osm_id, osm.name, osm.name_en, ne.scalerank, ne.labelrank + FROM ne_10m_populated_places AS ne, + osm_city_point AS osm + WHERE ( + (osm.tags ? 'wikidata' AND osm.tags->'wikidata' = ne.wikidataid) OR + ne.name ILIKE osm.name OR + ne.name ILIKE osm.name_en OR + ne.namealt ILIKE osm.name OR + ne.namealt ILIKE osm.name_en OR + ne.meganame ILIKE osm.name OR + ne.meganame ILIKE osm.name_en OR + ne.gn_ascii ILIKE osm.name OR + ne.gn_ascii ILIKE osm.name_en OR + ne.nameascii ILIKE osm.name OR + ne.nameascii ILIKE osm.name_en OR + ne.name = unaccent(osm.name) + ) + AND osm.place IN ('city', 'town', 'village') + AND ST_DWithin(ne.geometry, osm.geometry, 50000) + ) + UPDATE osm_city_point AS osm + -- Move scalerank to range 1 to 10 and merge scalerank 5 with 6 since not enough cities + -- are in the scalerank 5 bucket + SET "rank" = CASE WHEN scalerank <= 5 THEN scalerank + 1 ELSE scalerank END + FROM important_city_point AS ne + WHERE osm.osm_id = ne.osm_id; - UPDATE osm_city_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_city_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; SELECT update_osm_city_point(); -CREATE INDEX IF NOT EXISTS osm_city_point_rank_idx ON osm_city_point("rank"); +CREATE INDEX IF NOT EXISTS osm_city_point_rank_idx ON osm_city_point ("rank"); -- Handle updates CREATE SCHEMA IF NOT EXISTS place_city; -CREATE TABLE IF NOT EXISTS place_city.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_city.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_city.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_city.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_city.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_city.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_city.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_city rank'; PERFORM update_osm_city_point(); + -- noinspection SqlWithoutWhere DELETE FROM place_city.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_city_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_city_point FOR EACH STATEMENT - EXECUTE PROCEDURE place_city.flag(); +EXECUTE PROCEDURE place_city.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_city.updates + AFTER INSERT + ON place_city.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_city.refresh(); \ No newline at end of file +EXECUTE PROCEDURE place_city.refresh(); diff --git a/layers/place/update_continent_point.sql b/layers/place/update_continent_point.sql index 9e48c54..6502299 100644 --- a/layers/place/update_continent_point.sql +++ b/layers/place/update_continent_point.sql @@ -2,11 +2,12 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_continent_point; DROP TRIGGER IF EXISTS trigger_refresh ON place_continent_point.updates; -- etldoc: osm_continent_point -> osm_continent_point -CREATE OR REPLACE FUNCTION update_osm_continent_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_continent_point() RETURNS void AS +$$ BEGIN - UPDATE osm_continent_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_continent_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -17,32 +18,40 @@ SELECT update_osm_continent_point(); CREATE SCHEMA IF NOT EXISTS place_continent_point; -CREATE TABLE IF NOT EXISTS place_continent_point.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_continent_point.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_continent_point.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_continent_point.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_continent_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_continent_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_continent_point.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_continent_point'; PERFORM update_osm_continent_point(); + -- noinspection SqlWithoutWhere DELETE FROM place_continent_point.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_continent_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_continent_point FOR EACH STATEMENT - EXECUTE PROCEDURE place_continent_point.flag(); +EXECUTE PROCEDURE place_continent_point.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_continent_point.updates + AFTER INSERT + ON place_continent_point.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_continent_point.refresh(); +EXECUTE PROCEDURE place_continent_point.refresh(); diff --git a/layers/place/update_country_point.sql b/layers/place/update_country_point.sql index 175a722..a49e3b6 100644 --- a/layers/place/update_country_point.sql +++ b/layers/place/update_country_point.sql @@ -1,80 +1,85 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_country_point; DROP TRIGGER IF EXISTS trigger_refresh ON place_country.updates; -ALTER TABLE osm_country_point DROP CONSTRAINT IF EXISTS osm_country_point_rank_constraint; +ALTER TABLE osm_country_point + DROP CONSTRAINT IF EXISTS osm_country_point_rank_constraint; -- etldoc: ne_10m_admin_0_countries -> osm_country_point -- etldoc: osm_country_point -> osm_country_point -CREATE OR REPLACE FUNCTION update_osm_country_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_country_point() RETURNS void AS +$$ BEGIN - UPDATE osm_country_point AS osm - SET - "rank" = 7, - iso3166_1_alpha_2 = COALESCE( - NULLIF(osm.country_code_iso3166_1_alpha_2, ''), - NULLIF(osm.iso3166_1_alpha_2, ''), - NULLIF(osm.iso3166_1, '') + UPDATE osm_country_point AS osm + SET "rank" = 7, + iso3166_1_alpha_2 = COALESCE( + NULLIF(osm.country_code_iso3166_1_alpha_2, ''), + NULLIF(osm.iso3166_1_alpha_2, ''), + NULLIF(osm.iso3166_1, '') + ); + + WITH important_country_point AS ( + SELECT osm.geometry, + osm.osm_id, + osm.name, + COALESCE(NULLIF(osm.name_en, ''), ne.name) AS name_en, + ne.scalerank, + ne.labelrank + FROM ne_10m_admin_0_countries AS ne, + osm_country_point AS osm + WHERE + -- We match only countries with ISO codes to eliminate disputed countries + iso3166_1_alpha_2 IS NOT NULL + -- that lies inside polygon of sovereign country + AND ST_Within(osm.geometry, ne.geometry) ) - ; + UPDATE osm_country_point AS osm + -- Normalize both scalerank and labelrank into a ranking system from 1 to 6 + -- where the ranks are still distributed uniform enough across all countries + SET "rank" = LEAST(6, CEILING((scalerank + labelrank) / 2.0)) + FROM important_country_point AS ne + WHERE osm.osm_id = ne.osm_id; - WITH important_country_point AS ( - SELECT osm.geometry, osm.osm_id, osm.name, COALESCE(NULLIF(osm.name_en, ''), ne.name) AS name_en, ne.scalerank, ne.labelrank - FROM ne_10m_admin_0_countries AS ne, osm_country_point AS osm - WHERE - -- We match only countries with ISO codes to eliminate disputed countries - iso3166_1_alpha_2 IS NOT NULL - -- that lies inside polygon of sovereign country - AND ST_Within(osm.geometry, ne.geometry) - ) - UPDATE osm_country_point AS osm - -- Normalize both scalerank and labelrank into a ranking system from 1 to 6 - -- where the ranks are still distributed uniform enough across all countries - SET "rank" = LEAST(6, CEILING((scalerank + labelrank)/2.0)) - FROM important_country_point AS ne - WHERE osm.osm_id = ne.osm_id; - - -- Repeat the step for archipelago countries like Philippines or Indonesia - -- whose label point is not within country's polygon - WITH important_country_point AS ( - SELECT - osm.osm_id, + -- Repeat the step for archipelago countries like Philippines or Indonesia + -- whose label point is not within country's polygon + WITH important_country_point AS ( + SELECT osm.osm_id, -- osm.name, - ne.scalerank, - ne.labelrank, + ne.scalerank, + ne.labelrank, -- ST_Distance(osm.geometry, ne.geometry) AS distance, - ROW_NUMBER() - OVER ( - PARTITION BY osm.osm_id - ORDER BY - ST_Distance(osm.geometry, ne.geometry) - ) AS rk - FROM osm_country_point osm, - ne_10m_admin_0_countries AS ne - WHERE - iso3166_1_alpha_2 IS NOT NULL - AND NOT (osm."rank" BETWEEN 1 AND 6) - ) - UPDATE osm_country_point AS osm - -- Normalize both scalerank and labelrank into a ranking system from 1 to 6 - -- where the ranks are still distributed uniform enough across all countries - SET "rank" = LEAST(6, CEILING((ne.scalerank + ne.labelrank)/2.0)) - FROM important_country_point AS ne - WHERE osm.osm_id = ne.osm_id AND ne.rk = 1; + ROW_NUMBER() + OVER ( + PARTITION BY osm.osm_id + ORDER BY + ST_Distance(osm.geometry, ne.geometry) + ) AS rk + FROM osm_country_point osm, + ne_10m_admin_0_countries AS ne + WHERE iso3166_1_alpha_2 IS NOT NULL + AND NOT (osm."rank" BETWEEN 1 AND 6) + ) + UPDATE osm_country_point AS osm + -- Normalize both scalerank and labelrank into a ranking system from 1 to 6 + -- where the ranks are still distributed uniform enough across all countries + SET "rank" = LEAST(6, CEILING((ne.scalerank + ne.labelrank) / 2.0)) + FROM important_country_point AS ne + WHERE osm.osm_id = ne.osm_id + AND ne.rk = 1; - UPDATE osm_country_point AS osm - SET "rank" = 6 - WHERE "rank" = 7; + UPDATE osm_country_point AS osm + SET "rank" = 6 + WHERE "rank" = 7; - -- TODO: This shouldn't be necessary? The rank function makes something wrong... - UPDATE osm_country_point AS osm - SET "rank" = 1 - WHERE "rank" = 0; + -- TODO: This shouldn't be necessary? The rank function makes something wrong... + UPDATE osm_country_point AS osm + SET "rank" = 1 + WHERE "rank" = 0; - UPDATE osm_country_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_country_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -82,38 +87,46 @@ $$ LANGUAGE plpgsql; SELECT update_osm_country_point(); -- ALTER TABLE osm_country_point ADD CONSTRAINT osm_country_point_rank_constraint CHECK("rank" BETWEEN 1 AND 6); -CREATE INDEX IF NOT EXISTS osm_country_point_rank_idx ON osm_country_point("rank"); +CREATE INDEX IF NOT EXISTS osm_country_point_rank_idx ON osm_country_point ("rank"); -- Handle updates CREATE SCHEMA IF NOT EXISTS place_country; -CREATE TABLE IF NOT EXISTS place_country.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_country.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_country.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_country.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_country.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_country.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_country.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_country rank'; PERFORM update_osm_country_point(); + -- noinspection SqlWithoutWhere DELETE FROM place_country.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_country_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_country_point FOR EACH STATEMENT - EXECUTE PROCEDURE place_country.flag(); +EXECUTE PROCEDURE place_country.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_country.updates + AFTER INSERT + ON place_country.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_country.refresh(); +EXECUTE PROCEDURE place_country.refresh(); diff --git a/layers/place/update_island_point.sql b/layers/place/update_island_point.sql index cedb646..b1c79f7 100644 --- a/layers/place/update_island_point.sql +++ b/layers/place/update_island_point.sql @@ -2,11 +2,12 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_island_point; DROP TRIGGER IF EXISTS trigger_refresh ON place_island_point.updates; -- etldoc: osm_island_point -> osm_island_point -CREATE OR REPLACE FUNCTION update_osm_island_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_island_point() RETURNS void AS +$$ BEGIN - UPDATE osm_island_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_island_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -17,32 +18,40 @@ SELECT update_osm_island_point(); CREATE SCHEMA IF NOT EXISTS place_island_point; -CREATE TABLE IF NOT EXISTS place_island_point.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_island_point.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_island_point.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_island_point.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_island_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_island_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_island_point.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_island_point'; PERFORM update_osm_island_point(); + -- noinspection SqlWithoutWhere DELETE FROM place_island_point.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_island_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_island_point FOR EACH STATEMENT - EXECUTE PROCEDURE place_island_point.flag(); +EXECUTE PROCEDURE place_island_point.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_island_point.updates + AFTER INSERT + ON place_island_point.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_island_point.refresh(); +EXECUTE PROCEDURE place_island_point.refresh(); diff --git a/layers/place/update_island_polygon.sql b/layers/place/update_island_polygon.sql index 29eebd3..9938373 100644 --- a/layers/place/update_island_polygon.sql +++ b/layers/place/update_island_polygon.sql @@ -2,15 +2,16 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_island_polygon; DROP TRIGGER IF EXISTS trigger_refresh ON place_island_polygon.updates; -- etldoc: osm_island_polygon -> osm_island_polygon -CREATE OR REPLACE FUNCTION update_osm_island_polygon() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_island_polygon() RETURNS void AS +$$ BEGIN - UPDATE osm_island_polygon SET geometry=ST_PointOnSurface(geometry) WHERE ST_GeometryType(geometry) <> 'ST_Point'; + UPDATE osm_island_polygon SET geometry=ST_PointOnSurface(geometry) WHERE ST_GeometryType(geometry) <> 'ST_Point'; - UPDATE osm_island_polygon - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_island_polygon + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; - ANALYZE osm_island_polygon; + ANALYZE osm_island_polygon; END; $$ LANGUAGE plpgsql; @@ -20,32 +21,40 @@ SELECT update_osm_island_polygon(); CREATE SCHEMA IF NOT EXISTS place_island_polygon; -CREATE TABLE IF NOT EXISTS place_island_polygon.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_island_polygon.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_island_polygon.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_island_polygon.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_island_polygon.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_island_polygon.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_island_polygon.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_island_polygon'; PERFORM update_osm_island_polygon(); + -- noinspection SqlWithoutWhere DELETE FROM place_island_polygon.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_island_polygon + AFTER INSERT OR UPDATE OR DELETE + ON osm_island_polygon FOR EACH STATEMENT - EXECUTE PROCEDURE place_island_polygon.flag(); +EXECUTE PROCEDURE place_island_polygon.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_island_polygon.updates + AFTER INSERT + ON place_island_polygon.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_island_polygon.refresh(); +EXECUTE PROCEDURE place_island_polygon.refresh(); diff --git a/layers/place/update_state_point.sql b/layers/place/update_state_point.sql index 878d6ad..4693d3c 100644 --- a/layers/place/update_state_point.sql +++ b/layers/place/update_state_point.sql @@ -1,40 +1,50 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_state_point; DROP TRIGGER IF EXISTS trigger_refresh ON place_state.updates; -ALTER TABLE osm_state_point DROP CONSTRAINT IF EXISTS osm_state_point_rank_constraint; +ALTER TABLE osm_state_point + DROP CONSTRAINT IF EXISTS osm_state_point_rank_constraint; -- etldoc: ne_10m_admin_1_states_provinces -> osm_state_point -- etldoc: osm_state_point -> osm_state_point -CREATE OR REPLACE FUNCTION update_osm_state_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_state_point() RETURNS void AS +$$ BEGIN - WITH important_state_point AS ( - SELECT osm.geometry, osm.osm_id, osm.name, COALESCE(NULLIF(osm.name_en, ''), ne.name) AS name_en, ne.scalerank, ne.labelrank, ne.datarank - FROM ne_10m_admin_1_states_provinces AS ne, osm_state_point AS osm - WHERE - -- We only match whether the point is within the Natural Earth polygon - -- because name matching is difficult - ST_Within(osm.geometry, ne.geometry) - -- We leave out leess important states - AND ne.scalerank <= 3 AND ne.labelrank <= 2 - ) - UPDATE osm_state_point AS osm - -- Normalize both scalerank and labelrank into a ranking system from 1 to 6. - SET "rank" = LEAST(6, CEILING((scalerank + labelrank + datarank)/3.0)) - FROM important_state_point AS ne - WHERE osm.osm_id = ne.osm_id; + WITH important_state_point AS ( + SELECT osm.geometry, + osm.osm_id, + osm.name, + COALESCE(NULLIF(osm.name_en, ''), ne.name) AS name_en, + ne.scalerank, + ne.labelrank, + ne.datarank + FROM ne_10m_admin_1_states_provinces AS ne, + osm_state_point AS osm + WHERE + -- We only match whether the point is within the Natural Earth polygon + -- because name matching is difficult + ST_Within(osm.geometry, ne.geometry) + -- We leave out leess important states + AND ne.scalerank <= 3 + AND ne.labelrank <= 2 + ) + UPDATE osm_state_point AS osm + -- Normalize both scalerank and labelrank into a ranking system from 1 to 6. + SET "rank" = LEAST(6, CEILING((scalerank + labelrank + datarank) / 3.0)) + FROM important_state_point AS ne + WHERE osm.osm_id = ne.osm_id; - -- TODO: This shouldn't be necessary? The rank function makes something wrong... - UPDATE osm_state_point AS osm - SET "rank" = 1 - WHERE "rank" = 0; + -- TODO: This shouldn't be necessary? The rank function makes something wrong... + UPDATE osm_state_point AS osm + SET "rank" = 1 + WHERE "rank" = 0; - DELETE FROM osm_state_point WHERE "rank" IS NULL; + DELETE FROM osm_state_point WHERE "rank" IS NULL; - UPDATE osm_state_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_state_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; @@ -42,38 +52,46 @@ $$ LANGUAGE plpgsql; SELECT update_osm_state_point(); -- ALTER TABLE osm_state_point ADD CONSTRAINT osm_state_point_rank_constraint CHECK("rank" BETWEEN 1 AND 6); -CREATE INDEX IF NOT EXISTS osm_state_point_rank_idx ON osm_state_point("rank"); +CREATE INDEX IF NOT EXISTS osm_state_point_rank_idx ON osm_state_point ("rank"); -- Handle updates CREATE SCHEMA IF NOT EXISTS place_state; -CREATE TABLE IF NOT EXISTS place_state.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION place_state.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS place_state.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION place_state.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO place_state.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO place_state.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION place_state.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh place_state rank'; PERFORM update_osm_state_point(); + -- noinspection SqlWithoutWhere DELETE FROM place_state.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_state_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_state_point FOR EACH STATEMENT - EXECUTE PROCEDURE place_state.flag(); +EXECUTE PROCEDURE place_state.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON place_state.updates + AFTER INSERT + ON place_state.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE place_state.refresh(); +EXECUTE PROCEDURE place_state.refresh(); diff --git a/layers/poi/class.sql b/layers/poi/class.sql index eea2319..a36fbdf 100644 --- a/layers/poi/class.sql +++ b/layers/poi/class.sql @@ -1,40 +1,40 @@ -CREATE OR REPLACE FUNCTION poi_class_rank(class TEXT) -RETURNS INT AS $$ - SELECT CASE class - WHEN 'hospital' THEN 20 - WHEN 'railway' THEN 40 - WHEN 'bus' THEN 50 - WHEN 'attraction' THEN 70 - WHEN 'harbor' THEN 75 - WHEN 'college' THEN 80 - WHEN 'school' THEN 85 - WHEN 'stadium' THEN 90 - WHEN 'zoo' THEN 95 - WHEN 'town_hall' THEN 100 - WHEN 'campsite' THEN 110 - WHEN 'cemetery' THEN 115 - WHEN 'park' THEN 120 - WHEN 'library' THEN 130 - WHEN 'police' THEN 135 - WHEN 'post' THEN 140 - WHEN 'golf' THEN 150 - WHEN 'shop' THEN 400 - WHEN 'grocery' THEN 500 - WHEN 'fast_food' THEN 600 - WHEN 'clothing_store' THEN 700 - WHEN 'bar' THEN 800 - ELSE 1000 - END; +CREATE OR REPLACE FUNCTION poi_class_rank(class text) + RETURNS int AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT CASE class + WHEN 'hospital' THEN 20 + WHEN 'railway' THEN 40 + WHEN 'bus' THEN 50 + WHEN 'attraction' THEN 70 + WHEN 'harbor' THEN 75 + WHEN 'college' THEN 80 + WHEN 'school' THEN 85 + WHEN 'stadium' THEN 90 + WHEN 'zoo' THEN 95 + WHEN 'town_hall' THEN 100 + WHEN 'campsite' THEN 110 + WHEN 'cemetery' THEN 115 + WHEN 'park' THEN 120 + WHEN 'library' THEN 130 + WHEN 'police' THEN 135 + WHEN 'post' THEN 140 + WHEN 'golf' THEN 150 + WHEN 'shop' THEN 400 + WHEN 'grocery' THEN 500 + WHEN 'fast_food' THEN 600 + WHEN 'clothing_store' THEN 700 + WHEN 'bar' THEN 800 + ELSE 1000 + END; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; -CREATE OR REPLACE FUNCTION poi_class(subclass TEXT, mapping_key TEXT) -RETURNS TEXT AS $$ - SELECT CASE - %%FIELD_MAPPING: class %% - ELSE subclass - END; +CREATE OR REPLACE FUNCTION poi_class(subclass text, mapping_key text) + RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT CASE + %%FIELD_MAPPING: class %% + ELSE subclass + END; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/poi/layer.sql b/layers/poi/layer.sql index 35c80e2..6458aa4 100644 --- a/layers/poi/layer.sql +++ b/layers/poi/layer.sql @@ -1,75 +1,98 @@ - -- etldoc: layer_poi[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_poi | z12 | z13 | z14+" ] ; CREATE OR REPLACE FUNCTION layer_poi(bbox geometry, zoom_level integer, pixel_width numeric) -RETURNS TABLE(osm_id bigint, geometry geometry, name text, name_en text, name_de text, tags hstore, class text, subclass text, agg_stop integer, layer integer, level integer, indoor integer, "rank" int) AS $$ - SELECT osm_id_hash AS osm_id, geometry, NULLIF(name, '') AS name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - poi_class(subclass, mapping_key) AS class, - CASE - WHEN subclass = 'information' - THEN NULLIF(information, '') - WHEN subclass = 'place_of_worship' - THEN NULLIF(religion, '') - WHEN subclass = 'pitch' - THEN NULLIF(sport, '') - ELSE subclass - END AS subclass, - agg_stop, - NULLIF(layer, 0) AS layer, - "level", - CASE WHEN indoor=TRUE THEN 1 END as indoor, - row_number() OVER ( - PARTITION BY LabelGrid(geometry, 100 * pixel_width) - ORDER BY CASE WHEN name = '' THEN 2000 ELSE poi_class_rank(poi_class(subclass, mapping_key)) END ASC - )::int AS "rank" - FROM ( - -- etldoc: osm_poi_point -> layer_poi:z12 - -- etldoc: osm_poi_point -> layer_poi:z13 - SELECT *, - osm_id*10 AS osm_id_hash FROM osm_poi_point - WHERE geometry && bbox - AND zoom_level BETWEEN 12 AND 13 - AND ((subclass='station' AND mapping_key = 'railway') - OR subclass IN ('halt', 'ferry_terminal')) - UNION ALL - - -- etldoc: osm_poi_point -> layer_poi:z14_ - SELECT *, - osm_id*10 AS osm_id_hash FROM osm_poi_point - WHERE geometry && bbox - AND zoom_level >= 14 - - UNION ALL - -- etldoc: osm_poi_polygon -> layer_poi:z12 - -- etldoc: osm_poi_polygon -> layer_poi:z13 - SELECT *, - NULL::INTEGER AS agg_stop, - CASE WHEN osm_id<0 THEN -osm_id*10+4 - ELSE osm_id*10+1 - END AS osm_id_hash - FROM osm_poi_polygon - WHERE geometry && bbox - AND zoom_level BETWEEN 12 AND 13 - AND ((subclass='station' AND mapping_key = 'railway') - OR subclass IN ('halt', 'ferry_terminal')) - - UNION ALL - -- etldoc: osm_poi_polygon -> layer_poi:z14_ - SELECT *, - NULL::INTEGER AS agg_stop, - CASE WHEN osm_id<0 THEN -osm_id*10+4 - ELSE osm_id*10+1 - END AS osm_id_hash - FROM osm_poi_polygon - WHERE geometry && bbox - AND zoom_level >= 14 - ) as poi_union - ORDER BY "rank" - ; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + class text, + subclass text, + agg_stop integer, + layer integer, + level integer, + indoor integer, + "rank" int + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id_hash AS osm_id, + geometry, + NULLIF(name, '') AS name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + poi_class(subclass, mapping_key) AS class, + CASE + WHEN subclass = 'information' + THEN NULLIF(information, '') + WHEN subclass = 'place_of_worship' + THEN NULLIF(religion, '') + WHEN subclass = 'pitch' + THEN NULLIF(sport, '') + ELSE subclass + END AS subclass, + agg_stop, + NULLIF(layer, 0) AS layer, + "level", + CASE WHEN indoor = TRUE THEN 1 END AS indoor, + row_number() OVER ( + PARTITION BY LabelGrid(geometry, 100 * pixel_width) + ORDER BY CASE WHEN name = '' THEN 2000 ELSE poi_class_rank(poi_class(subclass, mapping_key)) END ASC + )::int AS "rank" +FROM ( + -- etldoc: osm_poi_point -> layer_poi:z12 + -- etldoc: osm_poi_point -> layer_poi:z13 + SELECT *, + osm_id * 10 AS osm_id_hash + FROM osm_poi_point + WHERE geometry && bbox + AND zoom_level BETWEEN 12 AND 13 + AND ((subclass = 'station' AND mapping_key = 'railway') + OR subclass IN ('halt', 'ferry_terminal')) + + UNION ALL + + -- etldoc: osm_poi_point -> layer_poi:z14_ + SELECT *, + osm_id * 10 AS osm_id_hash + FROM osm_poi_point + WHERE geometry && bbox + AND zoom_level >= 14 + + UNION ALL + + -- etldoc: osm_poi_polygon -> layer_poi:z12 + -- etldoc: osm_poi_polygon -> layer_poi:z13 + SELECT *, + NULL::integer AS agg_stop, + CASE + WHEN osm_id < 0 THEN -osm_id * 10 + 4 + ELSE osm_id * 10 + 1 + END AS osm_id_hash + FROM osm_poi_polygon + WHERE geometry && bbox + AND zoom_level BETWEEN 12 AND 13 + AND ((subclass = 'station' AND mapping_key = 'railway') + OR subclass IN ('halt', 'ferry_terminal')) + + UNION ALL + + -- etldoc: osm_poi_polygon -> layer_poi:z14_ + SELECT *, + NULL::integer AS agg_stop, + CASE + WHEN osm_id < 0 THEN -osm_id * 10 + 4 + ELSE osm_id * 10 + 1 + END AS osm_id_hash + FROM osm_poi_polygon + WHERE geometry && bbox + AND zoom_level >= 14 + ) AS poi_union +ORDER BY "rank" +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/poi/poi_stop_agg.sql b/layers/poi/poi_stop_agg.sql index 4e4f40a..3b1e905 100644 --- a/layers/poi/poi_stop_agg.sql +++ b/layers/poi/poi_stop_agg.sql @@ -1,35 +1,31 @@ DROP MATERIALIZED VIEW IF EXISTS osm_poi_stop_centroid CASCADE; -CREATE MATERIALIZED VIEW osm_poi_stop_centroid AS ( - SELECT - uic_ref, - count(*) as count, - CASE WHEN count(*) > 2 THEN ST_Centroid(ST_UNION(geometry)) END AS centroid - FROM osm_poi_point - WHERE - nullif(uic_ref, '') IS NOT NULL - AND subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') - GROUP BY - uic_ref - HAVING - count(*) > 1 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_poi_stop_centroid AS +( +SELECT uic_ref, + count(*) AS count, + CASE WHEN count(*) > 2 THEN ST_Centroid(ST_UNION(geometry)) END AS centroid +FROM osm_poi_point +WHERE nullif(uic_ref, '') IS NOT NULL + AND subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') +GROUP BY uic_ref +HAVING count(*) > 1 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; DROP MATERIALIZED VIEW IF EXISTS osm_poi_stop_rank CASCADE; -CREATE MATERIALIZED VIEW osm_poi_stop_rank AS ( - SELECT - p.osm_id, +CREATE MATERIALIZED VIEW osm_poi_stop_rank AS +( +SELECT p.osm_id, -- p.uic_ref, -- p.subclass, - ROW_NUMBER() - OVER ( - PARTITION BY p.uic_ref - ORDER BY - p.subclass :: public_transport_stop_type NULLS LAST, - ST_Distance(c.centroid, p.geometry) - ) AS rk - FROM osm_poi_point p - INNER JOIN osm_poi_stop_centroid c ON (p.uic_ref = c.uic_ref) - WHERE - subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') - ORDER BY p.uic_ref, rk -) /* DELAY_MATERIALIZED_VIEW_CREATION */; + ROW_NUMBER() + OVER ( + PARTITION BY p.uic_ref + ORDER BY + p.subclass :: public_transport_stop_type NULLS LAST, + ST_Distance(c.centroid, p.geometry) + ) AS rk +FROM osm_poi_point p + INNER JOIN osm_poi_stop_centroid c ON (p.uic_ref = c.uic_ref) +WHERE subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') +ORDER BY p.uic_ref, rk + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; diff --git a/layers/poi/public_transport_stop_type.sql b/layers/poi/public_transport_stop_type.sql index 433aa17..fa37541 100644 --- a/layers/poi/public_transport_stop_type.sql +++ b/layers/poi/public_transport_stop_type.sql @@ -1,11 +1,12 @@ -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 - FROM pg_type - WHERE typname = 'public_transport_stop_type') THEN - CREATE TYPE public_transport_stop_type AS ENUM ( - 'subway', 'tram_stop', 'bus_station', 'bus_stop' - ); - END IF; -END +DO +$$ + BEGIN + IF NOT EXISTS(SELECT 1 + FROM pg_type + WHERE typname = 'public_transport_stop_type') THEN + CREATE TYPE public_transport_stop_type AS enum ( + 'subway', 'tram_stop', 'bus_station', 'bus_stop' + ); + END IF; + END $$; diff --git a/layers/poi/update_poi_point.sql b/layers/poi/update_poi_point.sql index bd6aeb4..d058b58 100644 --- a/layers/poi/update_poi_point.sql +++ b/layers/poi/update_poi_point.sql @@ -2,83 +2,95 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_poi_point; DROP TRIGGER IF EXISTS trigger_refresh ON poi_point.updates; -- etldoc: osm_poi_point -> osm_poi_point -CREATE OR REPLACE FUNCTION update_osm_poi_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_poi_point() RETURNS void AS +$$ BEGIN - UPDATE osm_poi_point + UPDATE osm_poi_point SET subclass = 'subway' - WHERE station = 'subway' and subclass='station'; + WHERE station = 'subway' + AND subclass = 'station'; - UPDATE osm_poi_point + UPDATE osm_poi_point SET subclass = 'halt' - WHERE funicular = 'yes' and subclass='station'; + WHERE funicular = 'yes' + AND subclass = 'station'; - UPDATE osm_poi_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_poi_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; SELECT update_osm_poi_point(); -CREATE OR REPLACE FUNCTION update_osm_poi_point_agg() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_poi_point_agg() RETURNS void AS +$$ BEGIN - UPDATE osm_poi_point p - SET agg_stop = CASE - WHEN p.subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') - THEN 1 - END; + UPDATE osm_poi_point p + SET agg_stop = CASE + WHEN p.subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') + THEN 1 + END; - UPDATE osm_poi_point p + UPDATE osm_poi_point p SET agg_stop = ( - CASE - WHEN p.subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') - AND r.rk IS NULL OR r.rk = 1 - THEN 1 - END) + CASE + WHEN p.subclass IN ('bus_stop', 'bus_station', 'tram_stop', 'subway') + AND r.rk IS NULL OR r.rk = 1 + THEN 1 + END) FROM osm_poi_stop_rank r - WHERE p.osm_id = r.osm_id - ; + WHERE p.osm_id = r.osm_id; END; $$ LANGUAGE plpgsql; -ALTER TABLE osm_poi_point ADD COLUMN IF NOT EXISTS agg_stop INTEGER DEFAULT NULL; +ALTER TABLE osm_poi_point + ADD COLUMN IF NOT EXISTS agg_stop integer DEFAULT NULL; SELECT update_osm_poi_point_agg(); -- Handle updates CREATE SCHEMA IF NOT EXISTS poi_point; -CREATE TABLE IF NOT EXISTS poi_point.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION poi_point.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS poi_point.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION poi_point.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO poi_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO poi_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION poi_point.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh poi_point'; PERFORM update_osm_poi_point(); REFRESH MATERIALIZED VIEW osm_poi_stop_centroid; REFRESH MATERIALIZED VIEW osm_poi_stop_rank; PERFORM update_osm_poi_point_agg(); + -- noinspection SqlWithoutWhere DELETE FROM poi_point.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_poi_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_poi_point FOR EACH STATEMENT - EXECUTE PROCEDURE poi_point.flag(); +EXECUTE PROCEDURE poi_point.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON poi_point.updates + AFTER INSERT + ON poi_point.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE poi_point.refresh(); +EXECUTE PROCEDURE poi_point.refresh(); diff --git a/layers/poi/update_poi_polygon.sql b/layers/poi/update_poi_polygon.sql index ff6061d..d1b042f 100644 --- a/layers/poi/update_poi_polygon.sql +++ b/layers/poi/update_poi_polygon.sql @@ -3,29 +3,33 @@ DROP TRIGGER IF EXISTS trigger_refresh ON poi_polygon.updates; -- etldoc: osm_poi_polygon -> osm_poi_polygon -CREATE OR REPLACE FUNCTION update_poi_polygon() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_poi_polygon() RETURNS void AS +$$ BEGIN - UPDATE osm_poi_polygon - SET geometry = - CASE WHEN ST_NPoints(ST_ConvexHull(geometry))=ST_NPoints(geometry) - THEN ST_Centroid(geometry) - ELSE ST_PointOnSurface(geometry) - END - WHERE ST_GeometryType(geometry) <> 'ST_Point'; + UPDATE osm_poi_polygon + SET geometry = + CASE + WHEN ST_NPoints(ST_ConvexHull(geometry)) = ST_NPoints(geometry) + THEN ST_Centroid(geometry) + ELSE ST_PointOnSurface(geometry) + END + WHERE ST_GeometryType(geometry) <> 'ST_Point'; - UPDATE osm_poi_polygon - SET subclass = 'subway' - WHERE station = 'subway' and subclass='station'; + UPDATE osm_poi_polygon + SET subclass = 'subway' + WHERE station = 'subway' + AND subclass = 'station'; - UPDATE osm_poi_polygon + UPDATE osm_poi_polygon SET subclass = 'halt' - WHERE funicular = 'yes' and subclass='station'; + WHERE funicular = 'yes' + AND subclass = 'station'; - UPDATE osm_poi_polygon - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_poi_polygon + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; - ANALYZE osm_poi_polygon; + ANALYZE osm_poi_polygon; END; $$ LANGUAGE plpgsql; @@ -35,32 +39,40 @@ SELECT update_poi_polygon(); CREATE SCHEMA IF NOT EXISTS poi_polygon; -CREATE TABLE IF NOT EXISTS poi_polygon.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION poi_polygon.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS poi_polygon.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION poi_polygon.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO poi_polygon.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO poi_polygon.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION poi_polygon.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh poi_polygon'; PERFORM update_poi_polygon(); + -- noinspection SqlWithoutWhere DELETE FROM poi_polygon.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_poi_polygon + AFTER INSERT OR UPDATE OR DELETE + ON osm_poi_polygon FOR EACH STATEMENT - EXECUTE PROCEDURE poi_polygon.flag(); +EXECUTE PROCEDURE poi_polygon.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON poi_polygon.updates + AFTER INSERT + ON poi_polygon.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE poi_polygon.refresh(); +EXECUTE PROCEDURE poi_polygon.refresh(); diff --git a/layers/transportation/class.sql b/layers/transportation/class.sql index 43642ba..5777a05 100644 --- a/layers/transportation/class.sql +++ b/layers/transportation/class.sql @@ -1,51 +1,58 @@ -CREATE OR REPLACE FUNCTION brunnel(is_bridge BOOL, is_tunnel BOOL, is_ford BOOL) RETURNS TEXT AS $$ - SELECT CASE - WHEN is_bridge THEN 'bridge' - WHEN is_tunnel THEN 'tunnel' - WHEN is_ford THEN 'ford' - END; +CREATE OR REPLACE FUNCTION brunnel(is_bridge bool, is_tunnel bool, is_ford bool) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN is_bridge THEN 'bridge' + WHEN is_tunnel THEN 'tunnel' + WHEN is_ford THEN 'ford' + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -- The classes for highways are derived from the classes used in ClearTables -- https://github.com/ClearTables/ClearTables/blob/master/transportation.lua -CREATE OR REPLACE FUNCTION highway_class(highway TEXT, public_transport TEXT, construction TEXT) RETURNS TEXT AS $$ - SELECT CASE - %%FIELD_MAPPING: class %% - END; +CREATE OR REPLACE FUNCTION highway_class(highway text, public_transport text, construction text) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT CASE + %%FIELD_MAPPING: class %% + END; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; -- The classes for railways are derived from the classes used in ClearTables -- https://github.com/ClearTables/ClearTables/blob/master/transportation.lua -CREATE OR REPLACE FUNCTION railway_class(railway TEXT) RETURNS TEXT AS $$ - SELECT CASE - WHEN railway IN ('rail', 'narrow_gauge', 'preserved', 'funicular') THEN 'rail' - WHEN railway IN ('subway', 'light_rail', 'monorail', 'tram') THEN 'transit' - END; +CREATE OR REPLACE FUNCTION railway_class(railway text) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN railway IN ('rail', 'narrow_gauge', 'preserved', 'funicular') THEN 'rail' + WHEN railway IN ('subway', 'light_rail', 'monorail', 'tram') THEN 'transit' + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -- Limit service to only the most important values to ensure -- we always know the values of service -CREATE OR REPLACE FUNCTION service_value(service TEXT) RETURNS TEXT AS $$ - SELECT CASE - WHEN service IN ('spur', 'yard', 'siding', 'crossover', 'driveway', 'alley', 'parking_aisle') THEN service - END; +CREATE OR REPLACE FUNCTION service_value(service text) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN service IN ('spur', 'yard', 'siding', 'crossover', 'driveway', 'alley', 'parking_aisle') THEN service + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -- Limit surface to only the most important values to ensure -- we always know the values of surface -CREATE OR REPLACE FUNCTION surface_value(surface TEXT) RETURNS TEXT AS $$ - SELECT CASE - WHEN surface IN ('paved', 'asphalt', 'cobblestone', 'concrete', 'concrete:lanes', 'concrete:plates', 'metal', 'paving_stones', 'sett', 'unhewn_cobblestone', 'wood') THEN 'paved' - WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'gravel_turf', 'ground', 'ice', 'mud', 'pebblestone', 'salt', 'sand', 'snow', 'woodchips') THEN 'unpaved' - END; +CREATE OR REPLACE FUNCTION surface_value(surface text) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN surface IN ('paved', 'asphalt', 'cobblestone', 'concrete', 'concrete:lanes', 'concrete:plates', 'metal', + 'paving_stones', 'sett', 'unhewn_cobblestone', 'wood') THEN 'paved' + WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', + 'gravel_turf', 'ground', 'ice', 'mud', 'pebblestone', 'salt', 'sand', 'snow', 'woodchips') + THEN 'unpaved' + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; diff --git a/layers/transportation/layer.sql b/layers/transportation/layer.sql index 4b8bd88..e008b33 100644 --- a/layers/transportation/layer.sql +++ b/layers/transportation/layer.sql @@ -1,373 +1,702 @@ -CREATE OR REPLACE FUNCTION highway_is_link(highway TEXT) RETURNS BOOLEAN AS $$ - SELECT highway LIKE '%_link'; +CREATE OR REPLACE FUNCTION highway_is_link(highway text) RETURNS boolean AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT highway LIKE '%_link'; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -- etldoc: layer_transportation[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label=" layer_transportation | z4 | z5 | z6 | z7 | z8 | z9 | z10 | z11 | z12| z13| z14+" ] ; CREATE OR REPLACE FUNCTION layer_transportation(bbox geometry, zoom_level int) -RETURNS TABLE(osm_id bigint, geometry geometry, class text, subclass text, -ramp int, oneway int, brunnel TEXT, service TEXT, layer INT, level INT, -indoor INT, bicycle TEXT, foot TEXT, horse TEXT, mtb_scale TEXT, surface TEXT) AS $$ - SELECT - osm_id, geometry, - CASE - WHEN NULLIF(highway, '') IS NOT NULL OR NULLIF(public_transport, '') IS NOT NULL THEN highway_class(highway, public_transport, construction) - WHEN NULLIF(railway, '') IS NOT NULL THEN railway_class(railway) - WHEN NULLIF(aerialway, '') IS NOT NULL THEN aerialway - WHEN NULLIF(shipway, '') IS NOT NULL THEN shipway - WHEN NULLIF(man_made, '') IS NOT NULL THEN man_made - END AS class, - CASE - WHEN railway IS NOT NULL THEN railway - WHEN (highway IS NOT NULL OR public_transport IS NOT NULL) - AND highway_class(highway, public_transport, construction) = 'path' - THEN COALESCE(NULLIF(public_transport, ''), highway) - END AS subclass, - -- All links are considered as ramps as well - CASE WHEN highway_is_link(highway) OR highway = 'steps' - THEN 1 ELSE is_ramp::int END AS ramp, - is_oneway::int AS oneway, - brunnel(is_bridge, is_tunnel, is_ford) AS brunnel, - NULLIF(service, '') AS service, - NULLIF(layer, 0) AS layer, - "level", - CASE WHEN indoor=TRUE THEN 1 END as indoor, - NULLIF(bicycle, '') AS bicycle, - NULLIF(foot, '') AS foot, - NULLIF(horse, '') AS horse, - NULLIF(mtb_scale, '') AS mtb_scale, - NULLIF(surface, '') AS surface - FROM ( - -- etldoc: osm_transportation_merge_linestring_gen7 -> layer_transportation:z4 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_transportation_merge_linestring_gen7 - WHERE zoom_level = 4 - UNION ALL - - -- etldoc: osm_transportation_merge_linestring_gen6 -> layer_transportation:z5 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_transportation_merge_linestring_gen6 - WHERE zoom_level = 5 - UNION ALL - - -- etldoc: osm_transportation_merge_linestring_gen5 -> layer_transportation:z6 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_transportation_merge_linestring_gen5 - WHERE zoom_level = 6 - UNION ALL - - -- etldoc: osm_transportation_merge_linestring_gen4 -> layer_transportation:z7 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_transportation_merge_linestring_gen4 - WHERE zoom_level = 7 - UNION ALL - - -- etldoc: osm_transportation_merge_linestring_gen3 -> layer_transportation:z8 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_transportation_merge_linestring_gen3 - WHERE zoom_level = 8 - UNION ALL - - -- etldoc: osm_highway_linestring_gen2 -> layer_transportation:z9 - -- etldoc: osm_highway_linestring_gen2 -> layer_transportation:z10 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - bicycle, foot, horse, mtb_scale, - NULL AS surface, z_order - FROM osm_highway_linestring_gen2 - WHERE zoom_level BETWEEN 9 AND 10 - AND st_length(geometry)>zres(11) - UNION ALL - - -- etldoc: osm_highway_linestring_gen1 -> layer_transportation:z11 - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, NULL AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - bicycle, foot, horse, mtb_scale, - NULL AS surface, z_order - FROM osm_highway_linestring_gen1 - WHERE zoom_level = 11 - AND st_length(geometry)>zres(12) - UNION ALL - - -- etldoc: osm_highway_linestring -> layer_transportation:z12 - -- etldoc: osm_highway_linestring -> layer_transportation:z13 - -- etldoc: osm_highway_linestring -> layer_transportation:z14_ - SELECT - osm_id, geometry, - highway, construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, man_made, - layer, - CASE WHEN highway IN ('footway', 'steps') THEN "level" END AS "level", - CASE WHEN highway IN ('footway', 'steps') THEN indoor END AS indoor, - bicycle, foot, horse, mtb_scale, - surface_value(surface) AS "surface", - z_order - FROM osm_highway_linestring - WHERE NOT is_area AND ( - zoom_level = 12 AND ( - highway_class(highway, public_transport, construction) NOT IN ('track', 'path', 'minor') - OR highway IN ('unclassified', 'residential') - ) AND man_made <> 'pier' - OR zoom_level = 13 - AND ( - highway_class(highway, public_transport, construction) NOT IN ('track', 'path') AND man_made <> 'pier' - OR - man_made = 'pier' AND NOT ST_IsClosed(geometry) - ) - OR zoom_level >= 14 - AND ( - man_made <> 'pier' - OR - NOT ST_IsClosed(geometry) - ) - ) - UNION ALL - - -- etldoc: osm_railway_linestring_gen5 -> layer_transportation:z8 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL as surface, z_order - FROM osm_railway_linestring_gen5 - WHERE zoom_level = 8 - AND railway='rail' AND service = '' and usage='main' - UNION ALL - - -- etldoc: osm_railway_linestring_gen4 -> layer_transportation:z9 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, - NULL::boolean AS is_ford, - NULL::boolean AS is_ramp, NULL::int AS is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_railway_linestring_gen4 - WHERE zoom_level = 9 - AND railway='rail' AND service = '' and usage='main' - UNION ALL - - -- etldoc: osm_railway_linestring_gen3 -> layer_transportation:z10 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_railway_linestring_gen3 - WHERE zoom_level = 10 - AND railway IN ('rail', 'narrow_gauge') AND service = '' - UNION ALL - - -- etldoc: osm_railway_linestring_gen2 -> layer_transportation:z11 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL as surface, z_order - FROM osm_railway_linestring_gen2 - WHERE zoom_level = 11 - AND railway IN ('rail', 'narrow_gauge', 'light_rail') AND service = '' - UNION ALL - - -- etldoc: osm_railway_linestring_gen1 -> layer_transportation:z12 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL as surface, z_order - FROM osm_railway_linestring_gen1 - WHERE zoom_level = 12 - AND railway IN ('rail', 'narrow_gauge', 'light_rail') AND service = '' - UNION ALL - - -- etldoc: osm_railway_linestring -> layer_transportation:z13 - -- etldoc: osm_railway_linestring -> layer_transportation:z14_ - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, railway, NULL AS aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL as surface, z_order - FROM osm_railway_linestring - WHERE zoom_level = 13 - AND railway IN ('rail', 'narrow_gauge', 'light_rail') AND service = '' - OR zoom_Level >= 14 - UNION ALL - - -- etldoc: osm_aerialway_linestring_gen1 -> layer_transportation:z12 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, NULL as railway, aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_aerialway_linestring_gen1 - WHERE zoom_level = 12 - UNION ALL - - -- etldoc: osm_aerialway_linestring -> layer_transportation:z13 - -- etldoc: osm_aerialway_linestring -> layer_transportation:z14_ - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, NULL as railway, aerialway, NULL AS shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_aerialway_linestring - WHERE zoom_level >= 13 - UNION ALL - - -- etldoc: osm_shipway_linestring_gen2 -> layer_transportation:z11 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, NULL AS railway, NULL AS aerialway, shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_shipway_linestring_gen2 - WHERE zoom_level = 11 - UNION ALL - - -- etldoc: osm_shipway_linestring_gen1 -> layer_transportation:z12 - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, NULL AS railway, NULL AS aerialway, shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_shipway_linestring_gen1 - WHERE zoom_level = 12 - UNION ALL - - -- etldoc: osm_shipway_linestring -> layer_transportation:z13 - -- etldoc: osm_shipway_linestring -> layer_transportation:z14_ - SELECT - osm_id, geometry, - NULL AS highway, NULL AS construction, NULL AS railway, NULL AS aerialway, shipway, - NULL AS public_transport, service_value(service) AS service, - is_bridge, is_tunnel, is_ford, is_ramp, is_oneway, NULL as man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_shipway_linestring - WHERE zoom_level >= 13 - UNION ALL - - -- NOTE: We limit the selection of polys because we need to be - -- careful to net get false positives here because - -- it is possible that closed linestrings appear both as - -- highway linestrings and as polygon - -- etldoc: osm_highway_polygon -> layer_transportation:z13 - -- etldoc: osm_highway_polygon -> layer_transportation:z14_ - SELECT - osm_id, geometry, - highway, NULL AS construction, NULL AS railway, NULL AS aerialway, NULL AS shipway, - public_transport, NULL AS service, - CASE WHEN man_made IN ('bridge') THEN TRUE - ELSE FALSE - END AS is_bridge, FALSE AS is_tunnel, FALSE AS is_ford, - FALSE AS is_ramp, FALSE::int AS is_oneway, man_made, - layer, NULL::int AS level, NULL::boolean AS indoor, - NULL as bicycle, NULL as foot, NULL as horse, NULL as mtb_scale, - NULL AS surface, z_order - FROM osm_highway_polygon - -- We do not want underground pedestrian areas for now - WHERE zoom_level >= 13 - AND ( - man_made IN ('bridge', 'pier') - OR (is_area AND COALESCE(layer, 0) >= 0) + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + class text, + subclass text, + ramp int, + oneway int, + brunnel text, + service text, + layer int, + level int, + indoor int, + bicycle text, + foot text, + horse text, + mtb_scale text, + surface text ) - ) AS zoom_levels - WHERE geometry && bbox - ORDER BY z_order ASC; +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id, + geometry, + CASE + WHEN NULLIF(highway, '') IS NOT NULL OR NULLIF(public_transport, '') IS NOT NULL + THEN highway_class(highway, public_transport, construction) + WHEN NULLIF(railway, '') IS NOT NULL THEN railway_class(railway) + WHEN NULLIF(aerialway, '') IS NOT NULL THEN aerialway + WHEN NULLIF(shipway, '') IS NOT NULL THEN shipway + WHEN NULLIF(man_made, '') IS NOT NULL THEN man_made + END AS class, + CASE + WHEN railway IS NOT NULL THEN railway + WHEN (highway IS NOT NULL OR public_transport IS NOT NULL) + AND highway_class(highway, public_transport, construction) = 'path' + THEN COALESCE(NULLIF(public_transport, ''), highway) + END AS subclass, + -- All links are considered as ramps as well + CASE + WHEN highway_is_link(highway) OR highway = 'steps' + THEN 1 + ELSE is_ramp::int END AS ramp, + is_oneway::int AS oneway, + brunnel(is_bridge, is_tunnel, is_ford) AS brunnel, + NULLIF(service, '') AS service, + NULLIF(layer, 0) AS layer, + "level", + CASE WHEN indoor = TRUE THEN 1 END AS indoor, + NULLIF(bicycle, '') AS bicycle, + NULLIF(foot, '') AS foot, + NULLIF(horse, '') AS horse, + NULLIF(mtb_scale, '') AS mtb_scale, + NULLIF(surface, '') AS surface +FROM ( + -- etldoc: osm_transportation_merge_linestring_gen7 -> layer_transportation:z4 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_transportation_merge_linestring_gen7 + WHERE zoom_level = 4 + UNION ALL + + -- etldoc: osm_transportation_merge_linestring_gen6 -> layer_transportation:z5 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_transportation_merge_linestring_gen6 + WHERE zoom_level = 5 + UNION ALL + + -- etldoc: osm_transportation_merge_linestring_gen5 -> layer_transportation:z6 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_transportation_merge_linestring_gen5 + WHERE zoom_level = 6 + UNION ALL + + -- etldoc: osm_transportation_merge_linestring_gen4 -> layer_transportation:z7 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_transportation_merge_linestring_gen4 + WHERE zoom_level = 7 + UNION ALL + + -- etldoc: osm_transportation_merge_linestring_gen3 -> layer_transportation:z8 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_transportation_merge_linestring_gen3 + WHERE zoom_level = 8 + UNION ALL + + -- etldoc: osm_highway_linestring_gen2 -> layer_transportation:z9 + -- etldoc: osm_highway_linestring_gen2 -> layer_transportation:z10 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + bicycle, + foot, + horse, + mtb_scale, + NULL AS surface, + z_order + FROM osm_highway_linestring_gen2 + WHERE zoom_level BETWEEN 9 AND 10 + AND st_length(geometry) > zres(11) + UNION ALL + + -- etldoc: osm_highway_linestring_gen1 -> layer_transportation:z11 + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + NULL AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + bicycle, + foot, + horse, + mtb_scale, + NULL AS surface, + z_order + FROM osm_highway_linestring_gen1 + WHERE zoom_level = 11 + AND st_length(geometry) > zres(12) + UNION ALL + + -- etldoc: osm_highway_linestring -> layer_transportation:z12 + -- etldoc: osm_highway_linestring -> layer_transportation:z13 + -- etldoc: osm_highway_linestring -> layer_transportation:z14_ + SELECT osm_id, + geometry, + highway, + construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + man_made, + layer, + CASE WHEN highway IN ('footway', 'steps') THEN "level" END AS "level", + CASE WHEN highway IN ('footway', 'steps') THEN indoor END AS indoor, + bicycle, + foot, + horse, + mtb_scale, + surface_value(surface) AS "surface", + z_order + FROM osm_highway_linestring + WHERE NOT is_area + AND ( + zoom_level = 12 AND ( + highway_class(highway, public_transport, construction) NOT IN ('track', 'path', 'minor') + OR highway IN ('unclassified', 'residential') + ) AND man_made <> 'pier' + OR zoom_level = 13 + AND ( + highway_class(highway, public_transport, construction) NOT IN ('track', 'path') AND + man_made <> 'pier' + OR + man_made = 'pier' AND NOT ST_IsClosed(geometry) + ) + OR zoom_level >= 14 + AND ( + man_made <> 'pier' + OR + NOT ST_IsClosed(geometry) + ) + ) + UNION ALL + + -- etldoc: osm_railway_linestring_gen5 -> layer_transportation:z8 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring_gen5 + WHERE zoom_level = 8 + AND railway = 'rail' + AND service = '' + AND usage = 'main' + UNION ALL + + -- etldoc: osm_railway_linestring_gen4 -> layer_transportation:z9 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_ford, + NULL::boolean AS is_ramp, + NULL::int AS is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring_gen4 + WHERE zoom_level = 9 + AND railway = 'rail' + AND service = '' + AND usage = 'main' + UNION ALL + + -- etldoc: osm_railway_linestring_gen3 -> layer_transportation:z10 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring_gen3 + WHERE zoom_level = 10 + AND railway IN ('rail', 'narrow_gauge') + AND service = '' + UNION ALL + + -- etldoc: osm_railway_linestring_gen2 -> layer_transportation:z11 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring_gen2 + WHERE zoom_level = 11 + AND railway IN ('rail', 'narrow_gauge', 'light_rail') + AND service = '' + UNION ALL + + -- etldoc: osm_railway_linestring_gen1 -> layer_transportation:z12 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring_gen1 + WHERE zoom_level = 12 + AND railway IN ('rail', 'narrow_gauge', 'light_rail') + AND service = '' + UNION ALL + + -- etldoc: osm_railway_linestring -> layer_transportation:z13 + -- etldoc: osm_railway_linestring -> layer_transportation:z14_ + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + railway, + NULL AS aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_railway_linestring + WHERE zoom_level = 13 + AND railway IN ('rail', 'narrow_gauge', 'light_rail') AND service = '' + OR zoom_level >= 14 + UNION ALL + + -- etldoc: osm_aerialway_linestring_gen1 -> layer_transportation:z12 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + NULL AS railway, + aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_aerialway_linestring_gen1 + WHERE zoom_level = 12 + UNION ALL + + -- etldoc: osm_aerialway_linestring -> layer_transportation:z13 + -- etldoc: osm_aerialway_linestring -> layer_transportation:z14_ + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + NULL AS railway, + aerialway, + NULL AS shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_aerialway_linestring + WHERE zoom_level >= 13 + UNION ALL + + -- etldoc: osm_shipway_linestring_gen2 -> layer_transportation:z11 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + NULL AS railway, + NULL AS aerialway, + shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_shipway_linestring_gen2 + WHERE zoom_level = 11 + UNION ALL + + -- etldoc: osm_shipway_linestring_gen1 -> layer_transportation:z12 + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + NULL AS railway, + NULL AS aerialway, + shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_shipway_linestring_gen1 + WHERE zoom_level = 12 + UNION ALL + + -- etldoc: osm_shipway_linestring -> layer_transportation:z13 + -- etldoc: osm_shipway_linestring -> layer_transportation:z14_ + SELECT osm_id, + geometry, + NULL AS highway, + NULL AS construction, + NULL AS railway, + NULL AS aerialway, + shipway, + NULL AS public_transport, + service_value(service) AS service, + is_bridge, + is_tunnel, + is_ford, + is_ramp, + is_oneway, + NULL AS man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_shipway_linestring + WHERE zoom_level >= 13 + UNION ALL + + -- NOTE: We limit the selection of polys because we need to be + -- careful to net get false positives here because + -- it is possible that closed linestrings appear both as + -- highway linestrings and as polygon + -- etldoc: osm_highway_polygon -> layer_transportation:z13 + -- etldoc: osm_highway_polygon -> layer_transportation:z14_ + SELECT osm_id, + geometry, + highway, + NULL AS construction, + NULL AS railway, + NULL AS aerialway, + NULL AS shipway, + public_transport, + NULL AS service, + CASE + WHEN man_made IN ('bridge') THEN TRUE + ELSE FALSE + END AS is_bridge, + FALSE AS is_tunnel, + FALSE AS is_ford, + FALSE AS is_ramp, + FALSE::int AS is_oneway, + man_made, + layer, + NULL::int AS level, + NULL::boolean AS indoor, + NULL AS bicycle, + NULL AS foot, + NULL AS horse, + NULL AS mtb_scale, + NULL AS surface, + z_order + FROM osm_highway_polygon + -- We do not want underground pedestrian areas for now + WHERE zoom_level >= 13 + AND ( + man_made IN ('bridge', 'pier') + OR (is_area AND COALESCE(layer, 0) >= 0) + ) + ) AS zoom_levels +WHERE geometry && bbox +ORDER BY z_order ASC; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/transportation/update_transportation_merge.sql b/layers/transportation/update_transportation_merge.sql index 4c21900..962b1b5 100644 --- a/layers/transportation/update_transportation_merge.sql +++ b/layers/transportation/update_transportation_merge.sql @@ -17,113 +17,129 @@ DROP TRIGGER IF EXISTS trigger_refresh ON transportation.updates; -- Improve performance of the sql in transportation_name/network_type.sql CREATE INDEX IF NOT EXISTS osm_highway_linestring_highway_idx - ON osm_highway_linestring(highway); + ON osm_highway_linestring (highway); -- Improve performance of the sql below CREATE INDEX IF NOT EXISTS osm_highway_linestring_highway_partial_idx - ON osm_highway_linestring(highway) - WHERE highway IN ('motorway','trunk', 'primary', 'construction'); + ON osm_highway_linestring (highway) + WHERE highway IN ('motorway', 'trunk', 'primary', 'construction'); - -- etldoc: osm_highway_linestring -> osm_transportation_merge_linestring -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring AS ( - SELECT - (ST_Dump(geometry)).geom AS geometry, - NULL::bigint AS osm_id, - highway, construction, - z_order - FROM ( - SELECT - ST_LineMerge(ST_Collect(geometry)) AS geometry, - highway, construction, - min(z_order) AS z_order - FROM osm_highway_linestring - WHERE (highway IN ('motorway','trunk', 'primary') OR highway = 'construction' AND construction IN ('motorway','trunk', 'primary')) - AND ST_IsValid(geometry) - group by highway, construction - ) AS highway_union -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +-- etldoc: osm_highway_linestring -> osm_transportation_merge_linestring +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring AS +( +SELECT (ST_Dump(geometry)).geom AS geometry, + NULL::bigint AS osm_id, + highway, + construction, + z_order +FROM ( + SELECT ST_LineMerge(ST_Collect(geometry)) AS geometry, + highway, + construction, + min(z_order) AS z_order + FROM osm_highway_linestring + WHERE (highway IN ('motorway', 'trunk', 'primary') OR + highway = 'construction' AND construction IN ('motorway', 'trunk', 'primary')) + AND ST_IsValid(geometry) + GROUP BY highway, construction + ) AS highway_union + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_geometry_idx - ON osm_transportation_merge_linestring USING gist(geometry); + ON osm_transportation_merge_linestring USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_highway_partial_idx - ON osm_transportation_merge_linestring(highway, construction) - WHERE highway IN ('motorway','trunk', 'primary', 'construction'); + ON osm_transportation_merge_linestring (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'primary', 'construction'); -- etldoc: osm_transportation_merge_linestring -> osm_transportation_merge_linestring_gen3 -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen3 AS ( - SELECT ST_Simplify(geometry, 120) AS geometry, osm_id, highway, construction, z_order - FROM osm_transportation_merge_linestring - WHERE highway IN ('motorway','trunk', 'primary') - OR highway = 'construction' AND construction IN ('motorway','trunk', 'primary') -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen3 AS +( +SELECT ST_Simplify(geometry, 120) AS geometry, osm_id, highway, construction, z_order +FROM osm_transportation_merge_linestring +WHERE highway IN ('motorway', 'trunk', 'primary') + OR highway = 'construction' AND construction IN ('motorway', 'trunk', 'primary') + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen3_geometry_idx - ON osm_transportation_merge_linestring_gen3 USING gist(geometry); + ON osm_transportation_merge_linestring_gen3 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen3_highway_partial_idx - ON osm_transportation_merge_linestring_gen3(highway, construction) - WHERE highway IN ('motorway','trunk', 'primary', 'construction'); + ON osm_transportation_merge_linestring_gen3 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'primary', 'construction'); -- etldoc: osm_transportation_merge_linestring_gen3 -> osm_transportation_merge_linestring_gen4 -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen4 AS ( - SELECT ST_Simplify(geometry, 200) AS geometry, osm_id, highway, construction, z_order - FROM osm_transportation_merge_linestring_gen3 - WHERE (highway IN ('motorway','trunk', 'primary') OR highway = 'construction' AND construction IN ('motorway','trunk', 'primary')) - AND ST_Length(geometry) > 50 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen4 AS +( +SELECT ST_Simplify(geometry, 200) AS geometry, osm_id, highway, construction, z_order +FROM osm_transportation_merge_linestring_gen3 +WHERE (highway IN ('motorway', 'trunk', 'primary') OR + highway = 'construction' AND construction IN ('motorway', 'trunk', 'primary')) + AND ST_Length(geometry) > 50 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen4_geometry_idx - ON osm_transportation_merge_linestring_gen4 USING gist(geometry); + ON osm_transportation_merge_linestring_gen4 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen4_highway_partial_idx - ON osm_transportation_merge_linestring_gen4(highway, construction) - WHERE highway IN ('motorway','trunk', 'primary', 'construction'); + ON osm_transportation_merge_linestring_gen4 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'primary', 'construction'); -- etldoc: osm_transportation_merge_linestring_gen4 -> osm_transportation_merge_linestring_gen5 -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen5 AS ( - SELECT ST_Simplify(geometry, 500) AS geometry, osm_id, highway, construction, z_order - FROM osm_transportation_merge_linestring_gen4 - WHERE (highway IN ('motorway','trunk') OR highway = 'construction' AND construction IN ('motorway','trunk')) - AND ST_Length(geometry) > 100 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen5 AS +( +SELECT ST_Simplify(geometry, 500) AS geometry, osm_id, highway, construction, z_order +FROM osm_transportation_merge_linestring_gen4 +WHERE (highway IN ('motorway', 'trunk') OR highway = 'construction' AND construction IN ('motorway', 'trunk')) + AND ST_Length(geometry) > 100 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen5_geometry_idx - ON osm_transportation_merge_linestring_gen5 USING gist(geometry); + ON osm_transportation_merge_linestring_gen5 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen5_highway_partial_idx - ON osm_transportation_merge_linestring_gen5(highway, construction) - WHERE highway IN ('motorway','trunk', 'construction'); + ON osm_transportation_merge_linestring_gen5 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'construction'); -- etldoc: osm_transportation_merge_linestring_gen5 -> osm_transportation_merge_linestring_gen6 -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen6 AS ( - SELECT ST_Simplify(geometry, 1000) AS geometry, osm_id, highway, construction, z_order - FROM osm_transportation_merge_linestring_gen5 - WHERE (highway IN ('motorway','trunk') OR highway = 'construction' AND construction IN ('motorway','trunk')) AND ST_Length(geometry) > 500 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen6 AS +( +SELECT ST_Simplify(geometry, 1000) AS geometry, osm_id, highway, construction, z_order +FROM osm_transportation_merge_linestring_gen5 +WHERE (highway IN ('motorway', 'trunk') OR highway = 'construction' AND construction IN ('motorway', 'trunk')) + AND ST_Length(geometry) > 500 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen6_geometry_idx - ON osm_transportation_merge_linestring_gen6 USING gist(geometry); + ON osm_transportation_merge_linestring_gen6 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen6_highway_partial_idx - ON osm_transportation_merge_linestring_gen6(highway, construction) - WHERE highway IN ('motorway','trunk', 'construction'); + ON osm_transportation_merge_linestring_gen6 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'construction'); -- etldoc: osm_transportation_merge_linestring_gen6 -> osm_transportation_merge_linestring_gen7 -CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen7 AS ( - SELECT ST_Simplify(geometry, 2000) AS geometry, osm_id, highway, construction, z_order - FROM osm_transportation_merge_linestring_gen6 - WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') AND ST_Length(geometry) > 1000 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE MATERIALIZED VIEW osm_transportation_merge_linestring_gen7 AS +( +SELECT ST_Simplify(geometry, 2000) AS geometry, osm_id, highway, construction, z_order +FROM osm_transportation_merge_linestring_gen6 +WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') + AND ST_Length(geometry) > 1000 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; CREATE INDEX IF NOT EXISTS osm_transportation_merge_linestring_gen7_geometry_idx - ON osm_transportation_merge_linestring_gen7 USING gist(geometry); + ON osm_transportation_merge_linestring_gen7 USING gist (geometry); -- Handle updates CREATE SCHEMA IF NOT EXISTS transportation; -CREATE TABLE IF NOT EXISTS transportation.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION transportation.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS transportation.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION transportation.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO transportation.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO transportation.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION transportation.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE NOTICE 'Refresh transportation'; REFRESH MATERIALIZED VIEW osm_transportation_merge_linestring; REFRESH MATERIALIZED VIEW osm_transportation_merge_linestring_gen3; @@ -131,19 +147,21 @@ CREATE OR REPLACE FUNCTION transportation.refresh() RETURNS trigger AS REFRESH MATERIALIZED VIEW osm_transportation_merge_linestring_gen5; REFRESH MATERIALIZED VIEW osm_transportation_merge_linestring_gen6; REFRESH MATERIALIZED VIEW osm_transportation_merge_linestring_gen7; + -- noinspection SqlWithoutWhere DELETE FROM transportation.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag_transportation - AFTER INSERT OR UPDATE OR DELETE ON osm_highway_linestring + AFTER INSERT OR UPDATE OR DELETE + ON osm_highway_linestring FOR EACH STATEMENT - EXECUTE PROCEDURE transportation.flag(); +EXECUTE PROCEDURE transportation.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON transportation.updates + AFTER INSERT + ON transportation.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE transportation.refresh(); +EXECUTE PROCEDURE transportation.refresh(); diff --git a/layers/transportation_name/layer.sql b/layers/transportation_name/layer.sql index ffc3a3d..9b0ea35 100644 --- a/layers/transportation_name/layer.sql +++ b/layers/transportation_name/layer.sql @@ -1,131 +1,151 @@ - -- etldoc: layer_transportation_name[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_transportation_name | z6 | z7 | z8 | z9 | z10 | z11 | z12| z13| z14+" ] ; CREATE OR REPLACE FUNCTION layer_transportation_name(bbox geometry, zoom_level integer) -RETURNS TABLE(osm_id bigint, geometry geometry, name text, name_en text, - name_de text, tags hstore, ref text, ref_length int, network text, class - text, subclass text, layer INT, level INT, indoor INT) AS $$ - SELECT osm_id, geometry, - NULLIF(name, '') AS name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - tags, - NULLIF(ref, ''), NULLIF(LENGTH(ref), 0) AS ref_length, - --TODO: The road network of the road is not yet implemented - case - when network is not null - then network::text - when length(coalesce(ref, ''))>0 - then 'road' - end as network, - highway_class(highway, '', construction) AS class, - CASE - WHEN highway IS NOT NULL AND highway_class(highway, '', construction) = 'path' - THEN highway - END AS subclass, - NULLIF(layer, 0) AS layer, - "level", - CASE WHEN indoor=TRUE THEN 1 END as indoor - FROM ( - - -- etldoc: osm_transportation_name_linestring_gen4 -> layer_transportation_name:z6 - SELECT *, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor - FROM osm_transportation_name_linestring_gen4 - WHERE zoom_level = 6 - UNION ALL - - -- etldoc: osm_transportation_name_linestring_gen3 -> layer_transportation_name:z7 - SELECT *, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor - FROM osm_transportation_name_linestring_gen3 - WHERE zoom_level = 7 - UNION ALL - - -- etldoc: osm_transportation_name_linestring_gen2 -> layer_transportation_name:z8 - SELECT *, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor - FROM osm_transportation_name_linestring_gen2 - WHERE zoom_level = 8 - UNION ALL - - -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z9 - -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z10 - -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z11 - SELECT *, - NULL::int AS layer, NULL::int AS level, NULL::boolean AS indoor - FROM osm_transportation_name_linestring_gen1 - WHERE zoom_level BETWEEN 9 AND 11 - UNION ALL - - -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z12 - SELECT - geometry, - osm_id, - name, - name_en, - name_de, - "tags", - ref, - highway, - construction, - network, - z_order, - layer, - "level", - indoor - FROM osm_transportation_name_linestring - WHERE zoom_level = 12 - AND LineLabel(zoom_level, COALESCE(NULLIF(name, ''), ref), geometry) - AND highway_class(highway, '', construction) NOT IN ('minor', 'track', 'path') - AND NOT highway_is_link(highway) - UNION ALL - - -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z13 - SELECT - geometry, - osm_id, - name, - name_en, - name_de, - "tags", - ref, - highway, - construction, - network, - z_order, - layer, - "level", - indoor - FROM osm_transportation_name_linestring - WHERE zoom_level = 13 - AND LineLabel(zoom_level, COALESCE(NULLIF(name, ''), ref), geometry) - AND highway_class(highway, '', construction) NOT IN ('track', 'path') - UNION ALL - - -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z14_ - SELECT - geometry, - osm_id, - name, - name_en, - name_de, - "tags", - ref, - highway, - construction, - network, - z_order, - layer, - "level", - indoor - FROM osm_transportation_name_linestring - WHERE zoom_level >= 14 - - ) AS zoom_levels - WHERE geometry && bbox - ORDER BY z_order ASC; + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + ref text, + ref_length int, + network text, + class text, + subclass text, + layer int, + level int, + indoor int + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT osm_id, + geometry, + NULLIF(name, '') AS name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + tags, + NULLIF(ref, ''), + NULLIF(LENGTH(ref), 0) AS ref_length, + --TODO: The road network of the road is not yet implemented + CASE + WHEN network IS NOT NULL + THEN network::text + WHEN length(coalesce(ref, '')) > 0 + THEN 'road' + END AS network, + highway_class(highway, '', construction) AS class, + CASE + WHEN highway IS NOT NULL AND highway_class(highway, '', construction) = 'path' + THEN highway + END AS subclass, + NULLIF(layer, 0) AS layer, + "level", + CASE WHEN indoor = TRUE THEN 1 END AS indoor +FROM ( + + -- etldoc: osm_transportation_name_linestring_gen4 -> layer_transportation_name:z6 + SELECT *, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor + FROM osm_transportation_name_linestring_gen4 + WHERE zoom_level = 6 + UNION ALL + + -- etldoc: osm_transportation_name_linestring_gen3 -> layer_transportation_name:z7 + SELECT *, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor + FROM osm_transportation_name_linestring_gen3 + WHERE zoom_level = 7 + UNION ALL + + -- etldoc: osm_transportation_name_linestring_gen2 -> layer_transportation_name:z8 + SELECT *, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor + FROM osm_transportation_name_linestring_gen2 + WHERE zoom_level = 8 + UNION ALL + + -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z9 + -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z10 + -- etldoc: osm_transportation_name_linestring_gen1 -> layer_transportation_name:z11 + SELECT *, + NULL::int AS layer, + NULL::int AS level, + NULL::boolean AS indoor + FROM osm_transportation_name_linestring_gen1 + WHERE zoom_level BETWEEN 9 AND 11 + UNION ALL + + -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z12 + SELECT geometry, + osm_id, + name, + name_en, + name_de, + "tags", + ref, + highway, + construction, + network, + z_order, + layer, + "level", + indoor + FROM osm_transportation_name_linestring + WHERE zoom_level = 12 + AND LineLabel(zoom_level, COALESCE(NULLIF(name, ''), ref), geometry) + AND highway_class(highway, '', construction) NOT IN ('minor', 'track', 'path') + AND NOT highway_is_link(highway) + UNION ALL + + -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z13 + SELECT geometry, + osm_id, + name, + name_en, + name_de, + "tags", + ref, + highway, + construction, + network, + z_order, + layer, + "level", + indoor + FROM osm_transportation_name_linestring + WHERE zoom_level = 13 + AND LineLabel(zoom_level, COALESCE(NULLIF(name, ''), ref), geometry) + AND highway_class(highway, '', construction) NOT IN ('track', 'path') + UNION ALL + + -- etldoc: osm_transportation_name_linestring -> layer_transportation_name:z14_ + SELECT geometry, + osm_id, + name, + name_en, + name_de, + "tags", + ref, + highway, + construction, + network, + z_order, + layer, + "level", + indoor + FROM osm_transportation_name_linestring + WHERE zoom_level >= 14 + ) AS zoom_levels +WHERE geometry && bbox +ORDER BY z_order ASC; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/transportation_name/network_type.sql b/layers/transportation_name/network_type.sql index 3250991..e207cb3 100644 --- a/layers/transportation_name/network_type.sql +++ b/layers/transportation_name/network_type.sql @@ -5,26 +5,27 @@ DROP MATERIALIZED VIEW IF EXISTS osm_transportation_name_linestring_gen2 CASCADE DROP MATERIALIZED VIEW IF EXISTS osm_transportation_name_linestring_gen3 CASCADE; DROP MATERIALIZED VIEW IF EXISTS osm_transportation_name_linestring_gen4 CASCADE; -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'route_network_type') THEN - CREATE TYPE route_network_type AS ENUM ( - 'us-interstate', 'us-highway', 'us-state', - 'ca-transcanada', - 'gb-motorway', 'gb-trunk' - ); - END IF; -END +DO $$ -; + BEGIN + IF NOT EXISTS(SELECT 1 FROM pg_type WHERE typname = 'route_network_type') THEN + CREATE TYPE route_network_type AS enum ( + 'us-interstate', 'us-highway', 'us-state', + 'ca-transcanada', + 'gb-motorway', 'gb-trunk' + ); + END IF; + END +$$; -DO $$ +DO +$$ BEGIN BEGIN - ALTER TABLE osm_route_member ADD COLUMN network_type route_network_type; + ALTER TABLE osm_route_member + ADD COLUMN network_type route_network_type; EXCEPTION WHEN duplicate_column THEN RAISE NOTICE 'column network_type already exists in network_type.'; END; END; -$$ -; +$$; diff --git a/layers/transportation_name/update_route_member.sql b/layers/transportation_name/update_route_member.sql index 19a9f16..178d94d 100644 --- a/layers/transportation_name/update_route_member.sql +++ b/layers/transportation_name/update_route_member.sql @@ -2,67 +2,69 @@ DROP TRIGGER IF EXISTS trigger_flag_transportation_name ON osm_route_member; -- create GBR relations (so we can use it in the same way as other relations) -CREATE OR REPLACE FUNCTION update_gbr_route_members() RETURNS VOID AS $$ -DECLARE gbr_geom geometry; +CREATE OR REPLACE FUNCTION update_gbr_route_members() RETURNS void AS +$$ +DECLARE + gbr_geom geometry; BEGIN - SELECT st_buffer(geometry, 10000) INTO gbr_geom FROM ne_10m_admin_0_countries where iso_a2 = 'GB'; + SELECT st_buffer(geometry, 10000) INTO gbr_geom FROM ne_10m_admin_0_countries WHERE iso_a2 = 'GB'; DELETE FROM osm_route_member WHERE network IN ('omt-gb-motorway', 'omt-gb-trunk'); INSERT INTO osm_route_member (osm_id, member, ref, network) - SELECT 0, osm_id, substring(ref FROM E'^[AM][0-9AM()]+'), - CASE WHEN highway = 'motorway' THEN 'omt-gb-motorway' ELSE 'omt-gb-trunk' END + SELECT 0, + osm_id, + substring(ref FROM E'^[AM][0-9AM()]+'), + CASE WHEN highway = 'motorway' THEN 'omt-gb-motorway' ELSE 'omt-gb-trunk' END FROM osm_highway_linestring - WHERE - length(ref)>0 AND - ST_Intersects(geometry, gbr_geom) AND - highway IN ('motorway', 'trunk') - ; + WHERE length(ref) > 0 + AND ST_Intersects(geometry, gbr_geom) + AND highway IN ('motorway', 'trunk'); END; $$ LANGUAGE plpgsql; -- etldoc: osm_route_member -> osm_route_member -CREATE OR REPLACE FUNCTION update_osm_route_member() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_route_member() RETURNS void AS +$$ BEGIN - PERFORM update_gbr_route_members(); + PERFORM update_gbr_route_members(); - -- see http://wiki.openstreetmap.org/wiki/Relation:route#Road_routes - UPDATE osm_route_member - SET network_type = - CASE - WHEN network = 'US:I' THEN 'us-interstate'::route_network_type - WHEN network = 'US:US' THEN 'us-highway'::route_network_type - WHEN network LIKE 'US:__' THEN 'us-state'::route_network_type - -- https://en.wikipedia.org/wiki/Trans-Canada_Highway - -- TODO: improve hierarchical queries using - -- http://www.openstreetmap.org/relation/1307243 - -- however the relation does not cover the whole Trans-Canada_Highway - WHEN - (network = 'CA:transcanada') OR - (network = 'CA:BC:primary' AND ref IN ('16')) OR - (name = 'Yellowhead Highway (AB)' AND ref IN ('16')) OR - (network = 'CA:SK:primary' AND ref IN ('16')) OR - (network = 'CA:ON:primary' AND ref IN ('17', '417')) OR - (name = 'Route Transcanadienne') OR - (network = 'CA:NB:primary' AND ref IN ('2', '16')) OR - (network = 'CA:PE' AND ref IN ('1')) OR - (network = 'CA:NS' AND ref IN ('104', '105')) OR - (network = 'CA:NL:R' AND ref IN ('1')) OR - (name = 'Trans-Canada Highway') - THEN 'ca-transcanada'::route_network_type - WHEN network = 'omt-gb-motorway' THEN 'gb-motorway'::route_network_type - WHEN network = 'omt-gb-trunk' THEN 'gb-trunk'::route_network_type - END - ; + -- see http://wiki.openstreetmap.org/wiki/Relation:route#Road_routes + UPDATE osm_route_member + SET network_type = + CASE + WHEN network = 'US:I' THEN 'us-interstate'::route_network_type + WHEN network = 'US:US' THEN 'us-highway'::route_network_type + WHEN network LIKE 'US:__' THEN 'us-state'::route_network_type + -- https://en.wikipedia.org/wiki/Trans-Canada_Highway + -- TODO: improve hierarchical queries using + -- http://www.openstreetmap.org/relation/1307243 + -- however the relation does not cover the whole Trans-Canada_Highway + WHEN + (network = 'CA:transcanada') OR + (network = 'CA:BC:primary' AND ref IN ('16')) OR + (name = 'Yellowhead Highway (AB)' AND ref IN ('16')) OR + (network = 'CA:SK:primary' AND ref IN ('16')) OR + (network = 'CA:ON:primary' AND ref IN ('17', '417')) OR + (name = 'Route Transcanadienne') OR + (network = 'CA:NB:primary' AND ref IN ('2', '16')) OR + (network = 'CA:PE' AND ref IN ('1')) OR + (network = 'CA:NS' AND ref IN ('104', '105')) OR + (network = 'CA:NL:R' AND ref IN ('1')) OR + (name = 'Trans-Canada Highway') + THEN 'ca-transcanada'::route_network_type + WHEN network = 'omt-gb-motorway' THEN 'gb-motorway'::route_network_type + WHEN network = 'omt-gb-trunk' THEN 'gb-trunk'::route_network_type + END; END; $$ LANGUAGE plpgsql; -CREATE INDEX IF NOT EXISTS osm_route_member_network_idx ON osm_route_member("network"); -CREATE INDEX IF NOT EXISTS osm_route_member_member_idx ON osm_route_member("member"); -CREATE INDEX IF NOT EXISTS osm_route_member_name_idx ON osm_route_member("name"); -CREATE INDEX IF NOT EXISTS osm_route_member_ref_idx ON osm_route_member("ref"); +CREATE INDEX IF NOT EXISTS osm_route_member_network_idx ON osm_route_member ("network"); +CREATE INDEX IF NOT EXISTS osm_route_member_member_idx ON osm_route_member ("member"); +CREATE INDEX IF NOT EXISTS osm_route_member_name_idx ON osm_route_member ("name"); +CREATE INDEX IF NOT EXISTS osm_route_member_ref_idx ON osm_route_member ("ref"); SELECT update_osm_route_member(); -CREATE INDEX IF NOT EXISTS osm_route_member_network_type_idx ON osm_route_member("network_type"); +CREATE INDEX IF NOT EXISTS osm_route_member_network_type_idx ON osm_route_member ("network_type"); diff --git a/layers/transportation_name/update_transportation_name.sql b/layers/transportation_name/update_transportation_name.sql index 236e9ac..ae4503a 100644 --- a/layers/transportation_name/update_transportation_name.sql +++ b/layers/transportation_name/update_transportation_name.sql @@ -9,139 +9,194 @@ DROP TRIGGER IF EXISTS trigger_refresh ON transportation_name.updates; -- etldoc: osm_highway_linestring -> osm_transportation_name_network -- etldoc: osm_route_member -> osm_transportation_name_network -CREATE MATERIALIZED VIEW osm_transportation_name_network AS ( - SELECT - hl.geometry, - hl.osm_id, - CASE WHEN length(hl.name)>15 THEN osml10n_street_abbrev_all(hl.name) ELSE hl.name END AS "name", - CASE WHEN length(hl.name_en)>15 THEN osml10n_street_abbrev_en(hl.name_en) ELSE hl.name_en END AS "name_en", - CASE WHEN length(hl.name_de)>15 THEN osml10n_street_abbrev_de(hl.name_de) ELSE hl.name_de END AS "name_de", - hl.tags, - rm.network_type, - CASE - WHEN (rm.network_type is not null AND nullif(rm.ref::text, '') is not null) - then rm.ref::text - else hl.ref - end as ref, - hl.highway, - hl.construction, - CASE WHEN highway IN ('footway', 'steps') THEN layer END AS layer, - CASE WHEN highway IN ('footway', 'steps') THEN "level" END AS "level", - CASE WHEN highway IN ('footway', 'steps') THEN indoor END AS indoor, - ROW_NUMBER() OVER(PARTITION BY hl.osm_id - ORDER BY rm.network_type) AS "rank", - hl.z_order - FROM osm_highway_linestring hl - left join osm_route_member rm on (rm.member = hl.osm_id) -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_network_geometry_idx ON osm_transportation_name_network USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_network AS +( +SELECT hl.geometry, + hl.osm_id, + CASE WHEN length(hl.name) > 15 THEN osml10n_street_abbrev_all(hl.name) ELSE hl.name END AS "name", + CASE WHEN length(hl.name_en) > 15 THEN osml10n_street_abbrev_en(hl.name_en) ELSE hl.name_en END AS "name_en", + CASE WHEN length(hl.name_de) > 15 THEN osml10n_street_abbrev_de(hl.name_de) ELSE hl.name_de END AS "name_de", + hl.tags, + rm.network_type, + CASE + WHEN (rm.network_type IS NOT NULL AND nullif(rm.ref::text, '') IS NOT NULL) + THEN rm.ref::text + ELSE hl.ref + END AS ref, + hl.highway, + hl.construction, + CASE WHEN highway IN ('footway', 'steps') THEN layer END AS layer, + CASE WHEN highway IN ('footway', 'steps') THEN "level" END AS "level", + CASE WHEN highway IN ('footway', 'steps') THEN indoor END AS indoor, + ROW_NUMBER() OVER (PARTITION BY hl.osm_id + ORDER BY rm.network_type) AS "rank", + hl.z_order +FROM osm_highway_linestring hl + LEFT JOIN osm_route_member rm ON (rm.member = hl.osm_id) + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_network_geometry_idx ON osm_transportation_name_network USING gist (geometry); -- etldoc: osm_transportation_name_network -> osm_transportation_name_linestring -CREATE MATERIALIZED VIEW osm_transportation_name_linestring AS ( - SELECT - (ST_Dump(geometry)).geom AS geometry, - NULL::bigint AS osm_id, - name, - name_en, - name_de, - tags || get_basic_names(tags, geometry) AS "tags", - ref, - highway, - construction, - "level", - layer, - indoor, - network_type AS network, - z_order - FROM ( - SELECT - ST_LineMerge(ST_Collect(geometry)) AS geometry, - name, - name_en, - name_de, - hstore(string_agg(nullif(slice_language_tags(tags || hstore(ARRAY['name', name, 'name:en', name_en, 'name:de', name_de]))::text, ''), ',')) - AS "tags", - ref, - highway, - construction, - "level", - layer, - indoor, - network_type, - min(z_order) AS z_order - FROM osm_transportation_name_network - WHERE ("rank"=1 OR "rank" is null) - AND (name <> '' OR ref <> '') - AND NULLIF(highway, '') IS NOT NULL - group by name, name_en, name_de, ref, highway, construction, "level", layer, indoor, network_type - ) AS highway_union -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_geometry_idx ON osm_transportation_name_linestring USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_linestring AS +( +SELECT (ST_Dump(geometry)).geom AS geometry, + NULL::bigint AS osm_id, + name, + name_en, + name_de, + tags || get_basic_names(tags, geometry) AS "tags", + ref, + highway, + construction, + "level", + layer, + indoor, + network_type AS network, + z_order +FROM ( + SELECT ST_LineMerge(ST_Collect(geometry)) AS geometry, + name, + name_en, + name_de, + hstore(string_agg(nullif(slice_language_tags(tags || + hstore(ARRAY ['name', name, 'name:en', name_en, 'name:de', name_de]))::text, + ''), ',')) + AS "tags", + ref, + highway, + construction, + "level", + layer, + indoor, + network_type, + min(z_order) AS z_order + FROM osm_transportation_name_network + WHERE ("rank" = 1 OR "rank" IS NULL) + AND (name <> '' OR ref <> '') + AND NULLIF(highway, '') IS NOT NULL + GROUP BY name, name_en, name_de, ref, highway, construction, "level", layer, indoor, network_type + ) AS highway_union + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_geometry_idx ON osm_transportation_name_linestring USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_highway_partial_idx - ON osm_transportation_name_linestring(highway, construction) - WHERE highway IN ('motorway','trunk', 'construction'); + ON osm_transportation_name_linestring (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'construction'); -- etldoc: osm_transportation_name_linestring -> osm_transportation_name_linestring_gen1 -CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen1 AS ( - SELECT ST_Simplify(geometry, 50) AS geometry, osm_id, name, name_en, name_de, tags, ref, highway, construction, network, z_order - FROM osm_transportation_name_linestring - WHERE (highway IN ('motorway','trunk') OR highway = 'construction' AND construction IN ('motorway','trunk')) AND ST_Length(geometry) > 8000 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen1_geometry_idx ON osm_transportation_name_linestring_gen1 USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen1 AS +( +SELECT ST_Simplify(geometry, 50) AS geometry, + osm_id, + name, + name_en, + name_de, + tags, + ref, + highway, + construction, + network, + z_order +FROM osm_transportation_name_linestring +WHERE (highway IN ('motorway', 'trunk') OR highway = 'construction' AND construction IN ('motorway', 'trunk')) + AND ST_Length(geometry) > 8000 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen1_geometry_idx ON osm_transportation_name_linestring_gen1 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen1_highway_partial_idx - ON osm_transportation_name_linestring_gen1(highway, construction) - WHERE highway IN ('motorway','trunk', 'construction'); + ON osm_transportation_name_linestring_gen1 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'construction'); -- etldoc: osm_transportation_name_linestring_gen1 -> osm_transportation_name_linestring_gen2 -CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen2 AS ( - SELECT ST_Simplify(geometry, 120) AS geometry, osm_id, name, name_en, name_de, tags, ref, highway, construction, network, z_order - FROM osm_transportation_name_linestring_gen1 - WHERE (highway IN ('motorway','trunk') OR highway = 'construction' AND construction IN ('motorway','trunk')) AND ST_Length(geometry) > 14000 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen2_geometry_idx ON osm_transportation_name_linestring_gen2 USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen2 AS +( +SELECT ST_Simplify(geometry, 120) AS geometry, + osm_id, + name, + name_en, + name_de, + tags, + ref, + highway, + construction, + network, + z_order +FROM osm_transportation_name_linestring_gen1 +WHERE (highway IN ('motorway', 'trunk') OR highway = 'construction' AND construction IN ('motorway', 'trunk')) + AND ST_Length(geometry) > 14000 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen2_geometry_idx ON osm_transportation_name_linestring_gen2 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen2_highway_partial_idx - ON osm_transportation_name_linestring_gen2(highway, construction) - WHERE highway IN ('motorway','trunk', 'construction'); + ON osm_transportation_name_linestring_gen2 (highway, construction) + WHERE highway IN ('motorway', 'trunk', 'construction'); -- etldoc: osm_transportation_name_linestring_gen2 -> osm_transportation_name_linestring_gen3 -CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen3 AS ( - SELECT ST_Simplify(geometry, 200) AS geometry, osm_id, name, name_en, name_de, tags, ref, highway, construction, network, z_order - FROM osm_transportation_name_linestring_gen2 - WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') AND ST_Length(geometry) > 20000 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen3_geometry_idx ON osm_transportation_name_linestring_gen3 USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen3 AS +( +SELECT ST_Simplify(geometry, 200) AS geometry, + osm_id, + name, + name_en, + name_de, + tags, + ref, + highway, + construction, + network, + z_order +FROM osm_transportation_name_linestring_gen2 +WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') + AND ST_Length(geometry) > 20000 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen3_geometry_idx ON osm_transportation_name_linestring_gen3 USING gist (geometry); CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen3_highway_partial_idx - ON osm_transportation_name_linestring_gen3(highway, construction) - WHERE highway IN ('motorway', 'construction'); + ON osm_transportation_name_linestring_gen3 (highway, construction) + WHERE highway IN ('motorway', 'construction'); -- etldoc: osm_transportation_name_linestring_gen3 -> osm_transportation_name_linestring_gen4 -CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen4 AS ( - SELECT ST_Simplify(geometry, 500) AS geometry, osm_id, name, name_en, name_de, tags, ref, highway, construction, network, z_order - FROM osm_transportation_name_linestring_gen3 - WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') AND ST_Length(geometry) > 20000 -) /* DELAY_MATERIALIZED_VIEW_CREATION */; -CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen4_geometry_idx ON osm_transportation_name_linestring_gen4 USING gist(geometry); +CREATE MATERIALIZED VIEW osm_transportation_name_linestring_gen4 AS +( +SELECT ST_Simplify(geometry, 500) AS geometry, + osm_id, + name, + name_en, + name_de, + tags, + ref, + highway, + construction, + network, + z_order +FROM osm_transportation_name_linestring_gen3 +WHERE (highway = 'motorway' OR highway = 'construction' AND construction = 'motorway') + AND ST_Length(geometry) > 20000 + ) /* DELAY_MATERIALIZED_VIEW_CREATION */; +CREATE INDEX IF NOT EXISTS osm_transportation_name_linestring_gen4_geometry_idx ON osm_transportation_name_linestring_gen4 USING gist (geometry); -- Handle updates CREATE SCHEMA IF NOT EXISTS transportation_name; -CREATE TABLE IF NOT EXISTS transportation_name.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION transportation_name.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS transportation_name.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION transportation_name.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO transportation_name.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO transportation_name.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION transportation_name.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh transportation_name'; PERFORM update_osm_route_member(); REFRESH MATERIALIZED VIEW osm_transportation_name_network; @@ -150,24 +205,27 @@ CREATE OR REPLACE FUNCTION transportation_name.refresh() RETURNS trigger AS REFRESH MATERIALIZED VIEW osm_transportation_name_linestring_gen2; REFRESH MATERIALIZED VIEW osm_transportation_name_linestring_gen3; REFRESH MATERIALIZED VIEW osm_transportation_name_linestring_gen4; + -- noinspection SqlWithoutWhere DELETE FROM transportation_name.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag_transportation_name - AFTER INSERT OR UPDATE OR DELETE ON osm_route_member + AFTER INSERT OR UPDATE OR DELETE + ON osm_route_member FOR EACH STATEMENT - EXECUTE PROCEDURE transportation_name.flag(); +EXECUTE PROCEDURE transportation_name.flag(); CREATE TRIGGER trigger_flag_transportation_name - AFTER INSERT OR UPDATE OR DELETE ON osm_highway_linestring + AFTER INSERT OR UPDATE OR DELETE + ON osm_highway_linestring FOR EACH STATEMENT - EXECUTE PROCEDURE transportation_name.flag(); +EXECUTE PROCEDURE transportation_name.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON transportation_name.updates + AFTER INSERT + ON transportation_name.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE transportation_name.refresh(); +EXECUTE PROCEDURE transportation_name.refresh(); diff --git a/layers/water/water.sql b/layers/water/water.sql index a478428..391ac2a 100644 --- a/layers/water/water.sql +++ b/layers/water/water.sql @@ -1,384 +1,470 @@ -- This statement can be deleted after the water importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_ocean_polygon_gen1 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen1 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen1 DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen1 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen1 AS ( - SELECT ST_Simplify(geometry, 20) AS geometry - FROM osm_ocean_polygon -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen1 AS +( +SELECT ST_Simplify(geometry, 20) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen1_idx ON osm_ocean_polygon_gen1 USING gist (geometry); -- This statement can be deleted after the water importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_ocean_polygon_gen2 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen2 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen2 DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen2 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen2 AS ( - SELECT ST_Simplify(geometry, 40) AS geometry - FROM osm_ocean_polygon -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen2 AS +( +SELECT ST_Simplify(geometry, 40) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen2_idx ON osm_ocean_polygon_gen2 USING gist (geometry); -- This statement can be deleted after the water importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_ocean_polygon_gen3 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen3 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen3 DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen3 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen3 AS ( - SELECT ST_Simplify(geometry, 80) AS geometry - FROM osm_ocean_polygon -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen3 AS +( +SELECT ST_Simplify(geometry, 80) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen3_idx ON osm_ocean_polygon_gen3 USING gist (geometry); -- This statement can be deleted after the water importer image stops creating this object as a table -DO $$ BEGIN DROP TABLE IF EXISTS osm_ocean_polygon_gen4 CASCADE; EXCEPTION WHEN wrong_object_type THEN END; $$ language 'plpgsql'; +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen4 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + -- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen4 DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen4 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen4 AS ( - SELECT ST_Simplify(geometry, 160) AS geometry - FROM osm_ocean_polygon -) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen4 AS +( +SELECT ST_Simplify(geometry, 160) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen4_idx ON osm_ocean_polygon_gen4 USING gist (geometry); -CREATE OR REPLACE FUNCTION water_class(waterway TEXT) RETURNS TEXT AS $$ - SELECT CASE +CREATE OR REPLACE FUNCTION water_class(waterway text) RETURNS text AS +$$ +SELECT CASE %%FIELD_MAPPING: class %% ELSE 'river' - END; + END; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; + + +CREATE OR REPLACE FUNCTION waterway_brunnel(is_bridge bool, is_tunnel bool) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; - - -CREATE OR REPLACE FUNCTION waterway_brunnel(is_bridge BOOL, is_tunnel BOOL) RETURNS TEXT AS $$ - SELECT CASE - WHEN is_bridge THEN 'bridge' - WHEN is_tunnel THEN 'tunnel' - END; -$$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN is_bridge THEN 'bridge' + WHEN is_tunnel THEN 'tunnel' + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -CREATE OR REPLACE VIEW water_z0 AS ( - -- etldoc: ne_110m_ocean -> water_z0 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_110m_ocean - UNION ALL - -- etldoc: ne_110m_lakes -> water_z0 - SELECT geometry, - 'lake'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_110m_lakes -); +CREATE OR REPLACE VIEW water_z0 AS +( +-- etldoc: ne_110m_ocean -> water_z0 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_110m_ocean +UNION ALL +-- etldoc: ne_110m_lakes -> water_z0 +SELECT geometry, + 'lake'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_110m_lakes + ); -CREATE OR REPLACE VIEW water_z1 AS ( - -- etldoc: ne_110m_ocean -> water_z1 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_110m_ocean - UNION ALL - -- etldoc: ne_110m_lakes -> water_z1 - SELECT geometry, - 'lake'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_110m_lakes -); +CREATE OR REPLACE VIEW water_z1 AS +( +-- etldoc: ne_110m_ocean -> water_z1 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_110m_ocean +UNION ALL +-- etldoc: ne_110m_lakes -> water_z1 +SELECT geometry, + 'lake'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_110m_lakes + ); -CREATE OR REPLACE VIEW water_z2 AS ( - -- etldoc: ne_50m_ocean -> water_z2 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_50m_ocean - UNION ALL - -- etldoc: ne_50m_lakes -> water_z2 - SELECT geometry, - 'lake'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_50m_lakes -); +CREATE OR REPLACE VIEW water_z2 AS +( +-- etldoc: ne_50m_ocean -> water_z2 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_50m_ocean +UNION ALL +-- etldoc: ne_50m_lakes -> water_z2 +SELECT geometry, + 'lake'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_50m_lakes + ); -CREATE OR REPLACE VIEW water_z4 AS ( - -- etldoc: ne_50m_ocean -> water_z4 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_50m_ocean - UNION ALL - -- etldoc: ne_10m_lakes -> water_z4 - SELECT geometry, - 'lake'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_10m_lakes -); +CREATE OR REPLACE VIEW water_z4 AS +( +-- etldoc: ne_50m_ocean -> water_z4 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_50m_ocean +UNION ALL +-- etldoc: ne_10m_lakes -> water_z4 +SELECT geometry, + 'lake'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_10m_lakes + ); -CREATE OR REPLACE VIEW water_z5 AS ( - -- etldoc: ne_10m_ocean -> water_z5 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_10m_ocean - UNION ALL - -- etldoc: ne_10m_lakes -> water_z5 - SELECT geometry, - 'lake'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM ne_10m_lakes -); +CREATE OR REPLACE VIEW water_z5 AS +( +-- etldoc: ne_10m_ocean -> water_z5 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_10m_ocean +UNION ALL +-- etldoc: ne_10m_lakes -> water_z5 +SELECT geometry, + 'lake'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM ne_10m_lakes + ); -CREATE OR REPLACE VIEW water_z6 AS ( - -- etldoc: osm_ocean_polygon_gen4 -> water_z6 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen4 - UNION ALL - -- etldoc: osm_water_polygon_gen6 -> water_z6 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen6 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z6 AS +( +-- etldoc: osm_ocean_polygon_gen4 -> water_z6 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen4 +UNION ALL +-- etldoc: osm_water_polygon_gen6 -> water_z6 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen6 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z7 AS ( - -- etldoc: osm_ocean_polygon_gen4 -> water_z7 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen4 - UNION ALL - -- etldoc: osm_water_polygon_gen5 -> water_z7 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen5 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z7 AS +( +-- etldoc: osm_ocean_polygon_gen4 -> water_z7 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen4 +UNION ALL +-- etldoc: osm_water_polygon_gen5 -> water_z7 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen5 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z8 AS ( - -- etldoc: osm_ocean_polygon_gen4 -> water_z8 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen4 - UNION ALL - -- etldoc: osm_water_polygon_gen4 -> water_z8 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen4 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z8 AS +( +-- etldoc: osm_ocean_polygon_gen4 -> water_z8 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen4 +UNION ALL +-- etldoc: osm_water_polygon_gen4 -> water_z8 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen4 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z9 AS ( - -- etldoc: osm_ocean_polygon_gen3 -> water_z9 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen3 - UNION ALL - -- etldoc: osm_water_polygon_gen3 -> water_z9 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen3 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z9 AS +( +-- etldoc: osm_ocean_polygon_gen3 -> water_z9 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen3 +UNION ALL +-- etldoc: osm_water_polygon_gen3 -> water_z9 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen3 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z10 AS ( - -- etldoc: osm_ocean_polygon_gen2 -> water_z10 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen2 - UNION ALL - -- etldoc: osm_water_polygon_gen2 -> water_z10 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen2 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z10 AS +( +-- etldoc: osm_ocean_polygon_gen2 -> water_z10 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen2 +UNION ALL +-- etldoc: osm_water_polygon_gen2 -> water_z10 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen2 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z11 AS ( - -- etldoc: osm_ocean_polygon_gen1 -> water_z11 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon_gen1 - UNION ALL - -- etldoc: osm_water_polygon_gen1 -> water_z11 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_water_polygon_gen1 - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z11 AS +( +-- etldoc: osm_ocean_polygon_gen1 -> water_z11 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon_gen1 +UNION ALL +-- etldoc: osm_water_polygon_gen1 -> water_z11 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_water_polygon_gen1 +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z12 AS ( - -- etldoc: osm_ocean_polygon_gen1 -> water_z12 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon - UNION ALL - -- etldoc: osm_water_polygon -> water_z12 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - is_bridge, - is_tunnel - FROM osm_water_polygon - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z12 AS +( +-- etldoc: osm_ocean_polygon_gen1 -> water_z12 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon +UNION ALL +-- etldoc: osm_water_polygon -> water_z12 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + is_bridge, + is_tunnel +FROM osm_water_polygon +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z13 AS ( - -- etldoc: osm_ocean_polygon -> water_z13 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon - UNION ALL - -- etldoc: osm_water_polygon -> water_z13 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - is_bridge, - is_tunnel - FROM osm_water_polygon - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z13 AS +( +-- etldoc: osm_ocean_polygon -> water_z13 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon +UNION ALL +-- etldoc: osm_water_polygon -> water_z13 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + is_bridge, + is_tunnel +FROM osm_water_polygon +WHERE "natural" != 'bay' + ); -CREATE OR REPLACE VIEW water_z14 AS ( - -- etldoc: osm_ocean_polygon -> water_z14 - SELECT geometry, - 'ocean'::text AS class, - NULL::boolean AS is_intermittent, - NULL::boolean AS is_bridge, - NULL::boolean AS is_tunnel - FROM osm_ocean_polygon - UNION ALL - -- etldoc: osm_water_polygon -> water_z14 - SELECT geometry, - water_class(waterway) AS class, - is_intermittent, - is_bridge, - is_tunnel - FROM osm_water_polygon - WHERE "natural" != 'bay' -); +CREATE OR REPLACE VIEW water_z14 AS +( +-- etldoc: osm_ocean_polygon -> water_z14 +SELECT geometry, + 'ocean'::text AS class, + NULL::boolean AS is_intermittent, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel +FROM osm_ocean_polygon +UNION ALL +-- etldoc: osm_water_polygon -> water_z14 +SELECT geometry, + water_class(waterway) AS class, + is_intermittent, + is_bridge, + is_tunnel +FROM osm_water_polygon +WHERE "natural" != 'bay' + ); -- etldoc: layer_water [shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_water | z0|z1|z2|z3 | z4|z5|z6|z7| z8 | z9 | z10 | z11 | z12| z13| z14+" ] ; -CREATE OR REPLACE FUNCTION layer_water (bbox geometry, zoom_level int) -RETURNS TABLE(geometry geometry, class text, brunnel text, intermittent int) AS $$ - SELECT geometry, - class::text, - waterway_brunnel(is_bridge, is_tunnel) AS brunnel, - is_intermittent::int AS intermittent - FROM ( - -- etldoc: water_z0 -> layer_water:z0 - SELECT * FROM water_z0 WHERE zoom_level = 0 - UNION ALL - -- etldoc: water_z1 -> layer_water:z1 - SELECT * FROM water_z1 WHERE zoom_level = 1 - UNION ALL - -- etldoc: water_z2 -> layer_water:z2 - -- etldoc: water_z2 -> layer_water:z3 - SELECT * FROM water_z2 WHERE zoom_level BETWEEN 2 AND 3 - UNION ALL - -- etldoc: water_z4 -> layer_water:z4 - SELECT * FROM water_z4 WHERE zoom_level = 4 - UNION ALL - -- etldoc: water_z5 -> layer_water:z5 - SELECT * FROM water_z5 WHERE zoom_level = 5 - UNION ALL - -- etldoc: water_z6 -> layer_water:z6 - SELECT * FROM water_z6 WHERE zoom_level = 6 - UNION ALL - -- etldoc: water_z7 -> layer_water:z7 - SELECT * FROM water_z7 WHERE zoom_level = 7 - UNION ALL - -- etldoc: water_z8 -> layer_water:z8 - SELECT * FROM water_z8 WHERE zoom_level = 8 - UNION ALL - -- etldoc: water_z9 -> layer_water:z9 - SELECT * FROM water_z9 WHERE zoom_level = 9 - UNION ALL - -- etldoc: water_z10 -> layer_water:z10 - SELECT * FROM water_z10 WHERE zoom_level = 10 - UNION ALL - -- etldoc: water_z11 -> layer_water:z11 - SELECT * FROM water_z11 WHERE zoom_level = 11 - UNION ALL - -- etldoc: water_z12 -> layer_water:z12 - SELECT * FROM water_z12 WHERE zoom_level = 12 - UNION ALL - -- etldoc: water_z13 -> layer_water:z13 - SELECT * FROM water_z13 WHERE zoom_level = 13 - UNION ALL - -- etldoc: water_z14 -> layer_water:z14_ - SELECT * FROM water_z14 WHERE zoom_level >= 14 - ) AS zoom_levels - WHERE geometry && bbox; +CREATE OR REPLACE FUNCTION layer_water(bbox geometry, zoom_level int) + RETURNS TABLE + ( + geometry geometry, + class text, + brunnel text, + intermittent int + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT geometry, + class::text, + waterway_brunnel(is_bridge, is_tunnel) AS brunnel, + is_intermittent::int AS intermittent +FROM ( + -- etldoc: water_z0 -> layer_water:z0 + SELECT * + FROM water_z0 + WHERE zoom_level = 0 + UNION ALL + -- etldoc: water_z1 -> layer_water:z1 + SELECT * + FROM water_z1 + WHERE zoom_level = 1 + UNION ALL + -- etldoc: water_z2 -> layer_water:z2 + -- etldoc: water_z2 -> layer_water:z3 + SELECT * + FROM water_z2 + WHERE zoom_level BETWEEN 2 AND 3 + UNION ALL + -- etldoc: water_z4 -> layer_water:z4 + SELECT * + FROM water_z4 + WHERE zoom_level = 4 + UNION ALL + -- etldoc: water_z5 -> layer_water:z5 + SELECT * + FROM water_z5 + WHERE zoom_level = 5 + UNION ALL + -- etldoc: water_z6 -> layer_water:z6 + SELECT * + FROM water_z6 + WHERE zoom_level = 6 + UNION ALL + -- etldoc: water_z7 -> layer_water:z7 + SELECT * + FROM water_z7 + WHERE zoom_level = 7 + UNION ALL + -- etldoc: water_z8 -> layer_water:z8 + SELECT * + FROM water_z8 + WHERE zoom_level = 8 + UNION ALL + -- etldoc: water_z9 -> layer_water:z9 + SELECT * + FROM water_z9 + WHERE zoom_level = 9 + UNION ALL + -- etldoc: water_z10 -> layer_water:z10 + SELECT * + FROM water_z10 + WHERE zoom_level = 10 + UNION ALL + -- etldoc: water_z11 -> layer_water:z11 + SELECT * + FROM water_z11 + WHERE zoom_level = 11 + UNION ALL + -- etldoc: water_z12 -> layer_water:z12 + SELECT * + FROM water_z12 + WHERE zoom_level = 12 + UNION ALL + -- etldoc: water_z13 -> layer_water:z13 + SELECT * + FROM water_z13 + WHERE zoom_level = 13 + UNION ALL + -- etldoc: water_z14 -> layer_water:z14_ + SELECT * + FROM water_z14 + WHERE zoom_level >= 14 + ) AS zoom_levels +WHERE geometry && bbox; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/water_name/layer.sql b/layers/water_name/layer.sql index 0aab292..70a1d6b 100644 --- a/layers/water_name/layer.sql +++ b/layers/water_name/layer.sql @@ -1,59 +1,78 @@ - -- etldoc: layer_water_name[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_water_name | z0_8 | z9_13 | z14+" ] ; CREATE OR REPLACE FUNCTION layer_water_name(bbox geometry, zoom_level integer) -RETURNS TABLE(osm_id bigint, geometry geometry, name text, name_en text, name_de text, tags hstore, class text, intermittent int) AS $$ + RETURNS TABLE + ( + osm_id bigint, + geometry geometry, + name text, + name_en text, + name_de text, + tags hstore, + class text, + intermittent int + ) +AS +$$ +SELECT -- etldoc: osm_water_lakeline -> layer_water_name:z9_13 -- etldoc: osm_water_lakeline -> layer_water_name:z14_ - SELECT - CASE WHEN osm_id<0 THEN -osm_id*10+4 - ELSE osm_id*10+1 - END AS osm_id_hash, - geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, + CASE + WHEN osm_id < 0 THEN -osm_id * 10 + 4 + ELSE osm_id * 10 + 1 + END AS osm_id_hash, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, tags, - 'lake'::text AS class, - is_intermittent::int AS intermittent - FROM osm_water_lakeline - WHERE geometry && bbox - AND ((zoom_level BETWEEN 9 AND 13 AND LineLabel(zoom_level, NULLIF(name, ''), geometry)) - OR (zoom_level >= 14)) + 'lake'::text AS class, + is_intermittent::int AS intermittent +FROM osm_water_lakeline +WHERE geometry && bbox + AND ((zoom_level BETWEEN 9 AND 13 AND LineLabel(zoom_level, NULLIF(name, ''), geometry)) + OR (zoom_level >= 14)) +UNION ALL +SELECT -- etldoc: osm_water_point -> layer_water_name:z9_13 -- etldoc: osm_water_point -> layer_water_name:z14_ - UNION ALL - SELECT - CASE WHEN osm_id<0 THEN -osm_id*10+4 - ELSE osm_id*10+1 - END AS osm_id_hash, - geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, + CASE + WHEN osm_id < 0 THEN -osm_id * 10 + 4 + ELSE osm_id * 10 + 1 + END AS osm_id_hash, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, tags, - 'lake'::text AS class, - is_intermittent::int AS intermittent - FROM osm_water_point - WHERE geometry && bbox AND ( - (zoom_level BETWEEN 9 AND 13 AND area > 70000*2^(20-zoom_level)) + 'lake'::text AS class, + is_intermittent::int AS intermittent +FROM osm_water_point +WHERE geometry && bbox + AND ( + (zoom_level BETWEEN 9 AND 13 AND area > 70000 * 2 ^ (20 - zoom_level)) OR (zoom_level >= 14) ) +UNION ALL +SELECT -- etldoc: osm_marine_point -> layer_water_name:z0_8 -- etldoc: osm_marine_point -> layer_water_name:z9_13 -- etldoc: osm_marine_point -> layer_water_name:z14_ - UNION ALL - SELECT osm_id*10, geometry, name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, + osm_id * 10 AS osm_id_hash, + geometry, + name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, tags, - place::text AS class, - is_intermittent::int AS intermittent - FROM osm_marine_point - WHERE geometry && bbox AND ( + place::text AS class, + is_intermittent::int AS intermittent +FROM osm_marine_point +WHERE geometry && bbox + AND ( place = 'ocean' OR (zoom_level >= "rank" AND "rank" IS NOT NULL) OR (zoom_level >= 8) ); -$$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; diff --git a/layers/water_name/update_marine_point.sql b/layers/water_name/update_marine_point.sql index c33a506..8fec8d0 100644 --- a/layers/water_name/update_marine_point.sql +++ b/layers/water_name/update_marine_point.sql @@ -3,67 +3,77 @@ DROP TRIGGER IF EXISTS trigger_refresh ON water_name_marine.updates; CREATE EXTENSION IF NOT EXISTS unaccent; -CREATE OR REPLACE FUNCTION update_osm_marine_point() RETURNS VOID AS $$ +CREATE OR REPLACE FUNCTION update_osm_marine_point() RETURNS void AS +$$ BEGIN - -- etldoc: osm_marine_point -> osm_marine_point - UPDATE osm_marine_point AS osm SET "rank" = NULL WHERE "rank" IS NOT NULL; + -- etldoc: osm_marine_point -> osm_marine_point + UPDATE osm_marine_point AS osm SET "rank" = NULL WHERE "rank" IS NOT NULL; - -- etldoc: ne_10m_geography_marine_polys -> osm_marine_point - -- etldoc: osm_marine_point -> osm_marine_point + -- etldoc: ne_10m_geography_marine_polys -> osm_marine_point + -- etldoc: osm_marine_point -> osm_marine_point - WITH important_marine_point AS ( - SELECT osm.geometry, osm.osm_id, osm.name, osm.name_en, ne.scalerank, osm.is_intermittent - FROM ne_10m_geography_marine_polys AS ne, osm_marine_point AS osm - WHERE trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.name - OR trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.tags->'name:en' - OR trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.tags->'name:es' - OR osm.name ILIKE trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) || ' %' - ) - UPDATE osm_marine_point AS osm - SET "rank" = scalerank - FROM important_marine_point AS ne - WHERE osm.osm_id = ne.osm_id; + WITH important_marine_point AS ( + SELECT osm.geometry, osm.osm_id, osm.name, osm.name_en, ne.scalerank, osm.is_intermittent + FROM ne_10m_geography_marine_polys AS ne, + osm_marine_point AS osm + WHERE trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.name + OR trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.tags->'name:en' + OR trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) ILIKE osm.tags->'name:es' + OR osm.name ILIKE trim(regexp_replace(ne.name, '\\s+', ' ', 'g')) || ' %' + ) + UPDATE osm_marine_point AS osm + SET "rank" = scalerank + FROM important_marine_point AS ne + WHERE osm.osm_id = ne.osm_id; - UPDATE osm_marine_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; + UPDATE osm_marine_point + SET tags = update_tags(tags, geometry) + WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; END; $$ LANGUAGE plpgsql; SELECT update_osm_marine_point(); -CREATE INDEX IF NOT EXISTS osm_marine_point_rank_idx ON osm_marine_point("rank"); +CREATE INDEX IF NOT EXISTS osm_marine_point_rank_idx ON osm_marine_point ("rank"); -- Handle updates CREATE SCHEMA IF NOT EXISTS water_name_marine; -CREATE TABLE IF NOT EXISTS water_name_marine.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION water_name_marine.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS water_name_marine.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION water_name_marine.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO water_name_marine.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO water_name_marine.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION water_name_marine.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh water_name_marine rank'; PERFORM update_osm_marine_point(); + -- noinspection SqlWithoutWhere DELETE FROM water_name_marine.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_marine_point + AFTER INSERT OR UPDATE OR DELETE + ON osm_marine_point FOR EACH STATEMENT - EXECUTE PROCEDURE water_name_marine.flag(); +EXECUTE PROCEDURE water_name_marine.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON water_name_marine.updates + AFTER INSERT + ON water_name_marine.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE water_name_marine.refresh(); +EXECUTE PROCEDURE water_name_marine.refresh(); diff --git a/layers/water_name/update_water_lakeline.sql b/layers/water_name/update_water_lakeline.sql index b4ccb56..3c58e43 100644 --- a/layers/water_name/update_water_lakeline.sql +++ b/layers/water_name/update_water_lakeline.sql @@ -3,76 +3,89 @@ DROP TRIGGER IF EXISTS trigger_update_line ON osm_water_polygon; DROP TRIGGER IF EXISTS trigger_insert_line ON osm_water_polygon; CREATE OR REPLACE VIEW osm_water_lakeline_view AS - SELECT wp.osm_id, - ll.wkb_geometry AS geometry, - name, name_en, name_de, - update_tags(tags, ll.wkb_geometry) AS tags, - ST_Area(wp.geometry) AS area, - is_intermittent - FROM osm_water_polygon AS wp - INNER JOIN lake_centerline ll ON wp.osm_id = ll.osm_id - WHERE wp.name <> '' AND ST_IsValid(wp.geometry) -; +SELECT wp.osm_id, + ll.wkb_geometry AS geometry, + name, + name_en, + name_de, + update_tags(tags, ll.wkb_geometry) AS tags, + ST_Area(wp.geometry) AS area, + is_intermittent +FROM osm_water_polygon AS wp + INNER JOIN lake_centerline ll ON wp.osm_id = ll.osm_id +WHERE wp.name <> '' + AND ST_IsValid(wp.geometry); -- etldoc: osm_water_polygon -> osm_water_lakeline -- etldoc: lake_centerline -> osm_water_lakeline CREATE TABLE IF NOT EXISTS osm_water_lakeline AS -SELECT * FROM osm_water_lakeline_view; -DO $$ +SELECT * +FROM osm_water_lakeline_view; +DO +$$ BEGIN - ALTER TABLE osm_water_lakeline ADD CONSTRAINT osm_water_lakeline_pk PRIMARY KEY (osm_id); - EXCEPTION WHEN others then - RAISE NOTICE 'primary key osm_water_lakeline_pk already exists in osm_water_lakeline.'; + ALTER TABLE osm_water_lakeline + ADD CONSTRAINT osm_water_lakeline_pk PRIMARY KEY (osm_id); + EXCEPTION + WHEN OTHERS THEN + RAISE NOTICE 'primary key osm_water_lakeline_pk already exists in osm_water_lakeline.'; END; $$; -CREATE INDEX IF NOT EXISTS osm_water_lakeline_geometry_idx ON osm_water_lakeline USING gist(geometry); +CREATE INDEX IF NOT EXISTS osm_water_lakeline_geometry_idx ON osm_water_lakeline USING gist (geometry); -- Handle updates CREATE SCHEMA IF NOT EXISTS water_lakeline; -CREATE OR REPLACE FUNCTION water_lakeline.delete() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_lakeline.delete() RETURNS trigger AS +$$ BEGIN - DELETE FROM osm_water_lakeline - WHERE osm_water_lakeline.osm_id = OLD.osm_id ; + DELETE + FROM osm_water_lakeline + WHERE osm_water_lakeline.osm_id = OLD.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION water_lakeline.update() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_lakeline.update() RETURNS trigger AS +$$ BEGIN UPDATE osm_water_lakeline SET (osm_id, geometry, name, name_en, name_de, tags, area, is_intermittent) = - (SELECT * FROM osm_water_lakeline_view WHERE osm_water_lakeline_view.osm_id = NEW.osm_id) + (SELECT * FROM osm_water_lakeline_view WHERE osm_water_lakeline_view.osm_id = NEW.osm_id) WHERE osm_water_lakeline.osm_id = NEW.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION water_lakeline.insert() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_lakeline.insert() RETURNS trigger AS +$$ BEGIN INSERT INTO osm_water_lakeline SELECT * FROM osm_water_lakeline_view WHERE osm_water_lakeline_view.osm_id = NEW.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_delete_line - AFTER DELETE ON osm_water_polygon + AFTER DELETE + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_lakeline.delete(); +EXECUTE PROCEDURE water_lakeline.delete(); CREATE TRIGGER trigger_update_line - AFTER UPDATE ON osm_water_polygon + AFTER UPDATE + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_lakeline.update(); +EXECUTE PROCEDURE water_lakeline.update(); CREATE TRIGGER trigger_insert_line - AFTER INSERT ON osm_water_polygon + AFTER INSERT + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_lakeline.insert(); +EXECUTE PROCEDURE water_lakeline.insert(); diff --git a/layers/water_name/update_water_point.sql b/layers/water_name/update_water_point.sql index b8445b7..b954bfc 100644 --- a/layers/water_name/update_water_point.sql +++ b/layers/water_name/update_water_point.sql @@ -3,26 +3,32 @@ DROP TRIGGER IF EXISTS trigger_update_point ON osm_water_polygon; DROP TRIGGER IF EXISTS trigger_insert_point ON osm_water_polygon; CREATE OR REPLACE VIEW osm_water_point_view AS - SELECT - wp.osm_id, ST_PointOnSurface(wp.geometry) AS geometry, - wp.name, wp.name_en, wp.name_de, - update_tags(wp.tags, ST_PointOnSurface(wp.geometry)) AS tags, - ST_Area(wp.geometry) AS area, - wp.is_intermittent - FROM osm_water_polygon AS wp - LEFT JOIN lake_centerline ll ON wp.osm_id = ll.osm_id - WHERE ll.osm_id IS NULL AND wp.name <> '' -; +SELECT wp.osm_id, + ST_PointOnSurface(wp.geometry) AS geometry, + wp.name, + wp.name_en, + wp.name_de, + update_tags(wp.tags, ST_PointOnSurface(wp.geometry)) AS tags, + ST_Area(wp.geometry) AS area, + wp.is_intermittent +FROM osm_water_polygon AS wp + LEFT JOIN lake_centerline ll ON wp.osm_id = ll.osm_id +WHERE ll.osm_id IS NULL + AND wp.name <> ''; -- etldoc: osm_water_polygon -> osm_water_point -- etldoc: lake_centerline -> osm_water_point CREATE TABLE IF NOT EXISTS osm_water_point AS -SELECT * FROM osm_water_point_view; -DO $$ +SELECT * +FROM osm_water_point_view; +DO +$$ BEGIN - ALTER TABLE osm_water_point ADD CONSTRAINT osm_water_point_pk PRIMARY KEY (osm_id); - EXCEPTION WHEN others then - RAISE NOTICE 'primary key osm_water_point_pk already exists in osm_water_point.'; + ALTER TABLE osm_water_point + ADD CONSTRAINT osm_water_point_pk PRIMARY KEY (osm_id); + EXCEPTION + WHEN OTHERS THEN + RAISE NOTICE 'primary key osm_water_point_pk already exists in osm_water_point.'; END; $$; CREATE INDEX IF NOT EXISTS osm_water_point_geometry_idx ON osm_water_point USING gist (geometry); @@ -31,48 +37,55 @@ CREATE INDEX IF NOT EXISTS osm_water_point_geometry_idx ON osm_water_point USING CREATE SCHEMA IF NOT EXISTS water_point; -CREATE OR REPLACE FUNCTION water_point.delete() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_point.delete() RETURNS trigger AS +$$ BEGIN - DELETE FROM osm_water_point - WHERE osm_water_point.osm_id = OLD.osm_id ; + DELETE + FROM osm_water_point + WHERE osm_water_point.osm_id = OLD.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION water_point.update() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_point.update() RETURNS trigger AS +$$ BEGIN UPDATE osm_water_point SET (osm_id, geometry, name, name_en, name_de, tags, area, is_intermittent) = - (SELECT * FROM osm_water_point_view WHERE osm_water_point_view.osm_id = NEW.osm_id) + (SELECT * FROM osm_water_point_view WHERE osm_water_point_view.osm_id = NEW.osm_id) WHERE osm_water_point.osm_id = NEW.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION water_point.insert() RETURNS trigger AS $BODY$ +CREATE OR REPLACE FUNCTION water_point.insert() RETURNS trigger AS +$$ BEGIN INSERT INTO osm_water_point SELECT * FROM osm_water_point_view WHERE osm_water_point_view.osm_id = NEW.osm_id; - RETURN null; + RETURN NULL; END; -$BODY$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_delete_point - AFTER DELETE ON osm_water_polygon + AFTER DELETE + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_point.delete(); +EXECUTE PROCEDURE water_point.delete(); CREATE TRIGGER trigger_update_point - AFTER UPDATE ON osm_water_polygon + AFTER UPDATE + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_point.update(); +EXECUTE PROCEDURE water_point.update(); CREATE TRIGGER trigger_insert_point - AFTER INSERT ON osm_water_polygon + AFTER INSERT + ON osm_water_polygon FOR EACH ROW - EXECUTE PROCEDURE water_point.insert(); +EXECUTE PROCEDURE water_point.insert(); diff --git a/layers/waterway/update_important_waterway.sql b/layers/waterway/update_important_waterway.sql index 43227cf..51cace4 100644 --- a/layers/waterway/update_important_waterway.sql +++ b/layers/waterway/update_important_waterway.sql @@ -7,185 +7,227 @@ DROP TRIGGER IF EXISTS trigger_refresh ON waterway_important.updates; -- and also makes it possible to filter out too short rivers CREATE INDEX IF NOT EXISTS osm_waterway_linestring_waterway_partial_idx - ON osm_waterway_linestring(waterway) + ON osm_waterway_linestring (waterway) WHERE waterway = 'river'; CREATE INDEX IF NOT EXISTS osm_waterway_linestring_name_partial_idx - ON osm_waterway_linestring(name) + ON osm_waterway_linestring (name) WHERE name <> ''; -- etldoc: osm_waterway_linestring -> osm_important_waterway_linestring CREATE TABLE IF NOT EXISTS osm_important_waterway_linestring AS - SELECT - (ST_Dump(geometry)).geom AS geometry, - name, name_en, name_de, tags - FROM ( - SELECT - ST_LineMerge(ST_Union(geometry)) AS geometry, - name, name_en, name_de, slice_language_tags(tags) AS tags - FROM osm_waterway_linestring - WHERE name <> '' AND waterway = 'river' AND ST_IsValid(geometry) - GROUP BY name, name_en, name_de, slice_language_tags(tags) - ) AS waterway_union; -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_names ON osm_important_waterway_linestring(name); -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_geometry_idx ON osm_important_waterway_linestring USING gist(geometry); +SELECT (ST_Dump(geometry)).geom AS geometry, + name, + name_en, + name_de, + tags +FROM ( + SELECT ST_LineMerge(ST_Union(geometry)) AS geometry, + name, + name_en, + name_de, + slice_language_tags(tags) AS tags + FROM osm_waterway_linestring + WHERE name <> '' + AND waterway = 'river' + AND ST_IsValid(geometry) + GROUP BY name, name_en, name_de, slice_language_tags(tags) + ) AS waterway_union; +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_names ON osm_important_waterway_linestring (name); +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_geometry_idx ON osm_important_waterway_linestring USING gist (geometry); -- etldoc: osm_important_waterway_linestring -> osm_important_waterway_linestring_gen1 CREATE OR REPLACE VIEW osm_important_waterway_linestring_gen1_view AS - SELECT ST_Simplify(geometry, 60) AS geometry, name, name_en, name_de, tags - FROM osm_important_waterway_linestring - WHERE ST_Length(geometry) > 1000 -; +SELECT ST_Simplify(geometry, 60) AS geometry, name, name_en, name_de, tags +FROM osm_important_waterway_linestring +WHERE ST_Length(geometry) > 1000; + CREATE TABLE IF NOT EXISTS osm_important_waterway_linestring_gen1 AS -SELECT * FROM osm_important_waterway_linestring_gen1_view; -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen1_name_idx ON osm_important_waterway_linestring_gen1(name); -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen1_geometry_idx ON osm_important_waterway_linestring_gen1 USING gist(geometry); +SELECT * +FROM osm_important_waterway_linestring_gen1_view; +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen1_name_idx ON osm_important_waterway_linestring_gen1 (name); +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen1_geometry_idx ON osm_important_waterway_linestring_gen1 USING gist (geometry); -- etldoc: osm_important_waterway_linestring_gen1 -> osm_important_waterway_linestring_gen2 CREATE OR REPLACE VIEW osm_important_waterway_linestring_gen2_view AS - SELECT ST_Simplify(geometry, 100) AS geometry, name, name_en, name_de, tags - FROM osm_important_waterway_linestring_gen1 - WHERE ST_Length(geometry) > 4000 -; +SELECT ST_Simplify(geometry, 100) AS geometry, name, name_en, name_de, tags +FROM osm_important_waterway_linestring_gen1 +WHERE ST_Length(geometry) > 4000; + CREATE TABLE IF NOT EXISTS osm_important_waterway_linestring_gen2 AS -SELECT * FROM osm_important_waterway_linestring_gen2_view; -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen2_name_idx ON osm_important_waterway_linestring_gen2(name); -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen2_geometry_idx ON osm_important_waterway_linestring_gen2 USING gist(geometry); +SELECT * +FROM osm_important_waterway_linestring_gen2_view; +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen2_name_idx ON osm_important_waterway_linestring_gen2 (name); +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen2_geometry_idx ON osm_important_waterway_linestring_gen2 USING gist (geometry); -- etldoc: osm_important_waterway_linestring_gen2 -> osm_important_waterway_linestring_gen3 CREATE OR REPLACE VIEW osm_important_waterway_linestring_gen3_view AS - SELECT ST_Simplify(geometry, 200) AS geometry, name, name_en, name_de, tags - FROM osm_important_waterway_linestring_gen2 - WHERE ST_Length(geometry) > 8000 -; +SELECT ST_Simplify(geometry, 200) AS geometry, name, name_en, name_de, tags +FROM osm_important_waterway_linestring_gen2 +WHERE ST_Length(geometry) > 8000; + CREATE TABLE IF NOT EXISTS osm_important_waterway_linestring_gen3 AS -SELECT * FROM osm_important_waterway_linestring_gen3_view; -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen3_name_idx ON osm_important_waterway_linestring_gen3(name); -CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen3_geometry_idx ON osm_important_waterway_linestring_gen3 USING gist(geometry); +SELECT * +FROM osm_important_waterway_linestring_gen3_view; +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen3_name_idx ON osm_important_waterway_linestring_gen3 (name); +CREATE INDEX IF NOT EXISTS osm_important_waterway_linestring_gen3_geometry_idx ON osm_important_waterway_linestring_gen3 USING gist (geometry); -- Handle updates CREATE SCHEMA IF NOT EXISTS waterway_important; -CREATE TABLE IF NOT EXISTS waterway_important.changes( - id serial primary key, - is_old boolean, - name character varying, +CREATE TABLE IF NOT EXISTS waterway_important.changes +( + id serial PRIMARY KEY, + is_old boolean, + name character varying, name_en character varying, name_de character varying, - tags hstore, - unique (is_old, name, name_en, name_de, tags) + tags hstore, + UNIQUE (is_old, name, name_en, name_de, tags) ); -CREATE OR REPLACE FUNCTION waterway_important.store() RETURNS trigger AS $$ +CREATE OR REPLACE FUNCTION waterway_important.store() RETURNS trigger AS +$$ BEGIN - IF (TG_OP IN ('DELETE', 'UPDATE')) AND OLD.name <> '' AND OLD.waterway = 'river' THEN + IF (tg_op IN ('DELETE', 'UPDATE')) AND OLD.name <> '' AND OLD.waterway = 'river' THEN INSERT INTO waterway_important.changes(is_old, name, name_en, name_de, tags) - VALUES (true, OLD.name, OLD.name_en, OLD.name_de, slice_language_tags(OLD.tags)) + VALUES (TRUE, OLD.name, OLD.name_en, OLD.name_de, slice_language_tags(OLD.tags)) ON CONFLICT(is_old, name, name_en, name_de, tags) DO NOTHING; END IF; - IF (TG_OP IN ('UPDATE', 'INSERT')) AND NEW.name <> '' AND NEW.waterway = 'river' THEN + IF (tg_op IN ('UPDATE', 'INSERT')) AND NEW.name <> '' AND NEW.waterway = 'river' THEN INSERT INTO waterway_important.changes(is_old, name, name_en, name_de, tags) - VALUES (false, NEW.name, NEW.name_en, NEW.name_de, slice_language_tags(NEW.tags)) + VALUES (FALSE, NEW.name, NEW.name_en, NEW.name_de, slice_language_tags(NEW.tags)) ON CONFLICT(is_old, name, name_en, name_de, tags) DO NOTHING; END IF; RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; -CREATE TABLE IF NOT EXISTS waterway_important.updates(id serial primary key, t text, unique (t)); -CREATE OR REPLACE FUNCTION waterway_important.flag() RETURNS trigger AS $$ +CREATE TABLE IF NOT EXISTS waterway_important.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); +CREATE OR REPLACE FUNCTION waterway_important.flag() RETURNS trigger AS +$$ BEGIN - INSERT INTO waterway_important.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; - RETURN null; + INSERT INTO waterway_important.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; END; -$$ language plpgsql; +$$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION waterway_important.refresh() RETURNS trigger AS - $BODY$ - BEGIN +$$ +BEGIN RAISE LOG 'Refresh waterway'; -- REFRESH osm_important_waterway_linestring - DELETE FROM osm_important_waterway_linestring AS w - USING waterway_important.changes AS c - WHERE - c.is_old AND - w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND w.name_de IS NOT DISTINCT FROM c.name_de AND w.tags IS NOT DISTINCT FROM c.tags; + DELETE + FROM osm_important_waterway_linestring AS w + USING waterway_important.changes AS c + WHERE c.is_old + AND w.name = c.name + AND w.name_en IS NOT DISTINCT FROM c.name_en + AND w.name_de IS NOT DISTINCT FROM c.name_de + AND w.tags IS NOT DISTINCT FROM c.tags; INSERT INTO osm_important_waterway_linestring - SELECT - (ST_Dump(geometry)).geom AS geometry, - name, name_en, name_de, tags + SELECT (ST_Dump(geometry)).geom AS geometry, + name, + name_en, + name_de, + tags FROM ( - SELECT - ST_LineMerge(ST_Union(geometry)) AS geometry, - w.name, w.name_en, w.name_de, slice_language_tags(w.tags) AS tags - FROM osm_waterway_linestring AS w - JOIN waterway_important.changes AS c ON - w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND w.name_de IS NOT DISTINCT FROM c.name_de AND slice_language_tags(w.tags) IS NOT DISTINCT FROM c.tags - WHERE w.name <> '' AND w.waterway = 'river' AND ST_IsValid(geometry) AND - NOT c.is_old - GROUP BY w.name, w.name_en, w.name_de, slice_language_tags(w.tags) - ) AS waterway_union; + SELECT ST_LineMerge(ST_Union(geometry)) AS geometry, + w.name, + w.name_en, + w.name_de, + slice_language_tags(w.tags) AS tags + FROM osm_waterway_linestring AS w + JOIN waterway_important.changes AS c ON + w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND + w.name_de IS NOT DISTINCT FROM c.name_de AND + slice_language_tags(w.tags) IS NOT DISTINCT FROM c.tags + WHERE w.name <> '' + AND w.waterway = 'river' + AND ST_IsValid(geometry) + AND NOT c.is_old + GROUP BY w.name, w.name_en, w.name_de, slice_language_tags(w.tags) + ) AS waterway_union; -- REFRESH sm_important_waterway_linestring_gen1 - DELETE FROM osm_important_waterway_linestring_gen1 AS w - USING waterway_important.changes AS c - WHERE - c.is_old AND - w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND w.name_de IS NOT DISTINCT FROM c.name_de AND w.tags IS NOT DISTINCT FROM c.tags; + DELETE + FROM osm_important_waterway_linestring_gen1 AS w + USING waterway_important.changes AS c + WHERE c.is_old + AND w.name = c.name + AND w.name_en IS NOT DISTINCT FROM c.name_en + AND w.name_de IS NOT DISTINCT FROM c.name_de + AND w.tags IS NOT DISTINCT FROM c.tags; INSERT INTO osm_important_waterway_linestring_gen1 SELECT w.* FROM osm_important_waterway_linestring_gen1_view AS w - NATURAL JOIN waterway_important.changes AS c + NATURAL JOIN waterway_important.changes AS c WHERE NOT c.is_old; -- REFRESH osm_important_waterway_linestring_gen2 - DELETE FROM osm_important_waterway_linestring_gen2 AS w - USING waterway_important.changes AS c - WHERE - c.is_old AND - w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND w.name_de IS NOT DISTINCT FROM c.name_de AND w.tags IS NOT DISTINCT FROM c.tags; + DELETE + FROM osm_important_waterway_linestring_gen2 AS w + USING waterway_important.changes AS c + WHERE c.is_old + AND w.name = c.name + AND w.name_en IS NOT DISTINCT FROM c.name_en + AND w.name_de IS NOT DISTINCT FROM c.name_de + AND w.tags IS NOT DISTINCT FROM c.tags; INSERT INTO osm_important_waterway_linestring_gen2 SELECT w.* FROM osm_important_waterway_linestring_gen2_view AS w - NATURAL JOIN waterway_important.changes AS c + NATURAL JOIN waterway_important.changes AS c WHERE NOT c.is_old; -- REFRESH osm_important_waterway_linestring_gen3 - DELETE FROM osm_important_waterway_linestring_gen3 AS w - USING waterway_important.changes AS c - WHERE - c.is_old AND - w.name = c.name AND w.name_en IS NOT DISTINCT FROM c.name_en AND w.name_de IS NOT DISTINCT FROM c.name_de AND w.tags IS NOT DISTINCT FROM c.tags; + DELETE + FROM osm_important_waterway_linestring_gen3 AS w + USING waterway_important.changes AS c + WHERE c.is_old + AND w.name = c.name + AND w.name_en IS NOT DISTINCT FROM c.name_en + AND w.name_de IS NOT DISTINCT FROM c.name_de + AND w.tags IS NOT DISTINCT FROM c.tags; INSERT INTO osm_important_waterway_linestring_gen3 SELECT w.* FROM osm_important_waterway_linestring_gen3_view AS w - NATURAL JOIN waterway_important.changes AS c + NATURAL JOIN waterway_important.changes AS c WHERE NOT c.is_old; + -- noinspection SqlWithoutWhere DELETE FROM waterway_important.changes; + -- noinspection SqlWithoutWhere DELETE FROM waterway_important.updates; - RETURN null; - END; - $BODY$ -language plpgsql; + + RETURN NULL; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_store - AFTER INSERT OR UPDATE OR DELETE ON osm_waterway_linestring + AFTER INSERT OR UPDATE OR DELETE + ON osm_waterway_linestring FOR EACH ROW - EXECUTE PROCEDURE waterway_important.store(); +EXECUTE PROCEDURE waterway_important.store(); CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE ON osm_waterway_linestring + AFTER INSERT OR UPDATE OR DELETE + ON osm_waterway_linestring FOR EACH STATEMENT - EXECUTE PROCEDURE waterway_important.flag(); +EXECUTE PROCEDURE waterway_important.flag(); CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT ON waterway_important.updates + AFTER INSERT + ON waterway_important.updates INITIALLY DEFERRED FOR EACH ROW - EXECUTE PROCEDURE waterway_important.refresh(); +EXECUTE PROCEDURE waterway_important.refresh(); diff --git a/layers/waterway/update_waterway_linestring.sql b/layers/waterway/update_waterway_linestring.sql index e94c8c5..f23f6cd 100644 --- a/layers/waterway/update_waterway_linestring.sql +++ b/layers/waterway/update_waterway_linestring.sql @@ -1,36 +1,38 @@ DROP TRIGGER IF EXISTS trigger_flag ON osm_waterway_linestring; DROP TRIGGER IF EXISTS trigger_refresh ON osm_waterway_linestring; -DO $$ -BEGIN - update osm_waterway_linestring - SET tags = update_tags(tags, geometry); +DO +$$ + BEGIN + UPDATE osm_waterway_linestring + SET tags = update_tags(tags, geometry); - update osm_waterway_linestring_gen1 - SET tags = update_tags(tags, geometry); + UPDATE osm_waterway_linestring_gen1 + SET tags = update_tags(tags, geometry); - update osm_waterway_linestring_gen2 - SET tags = update_tags(tags, geometry); + UPDATE osm_waterway_linestring_gen2 + SET tags = update_tags(tags, geometry); - update osm_waterway_linestring_gen3 - SET tags = update_tags(tags, geometry); -END $$; + UPDATE osm_waterway_linestring_gen3 + SET tags = update_tags(tags, geometry); + END +$$; -- Handle updates CREATE SCHEMA IF NOT EXISTS waterway_linestring; CREATE OR REPLACE FUNCTION waterway_linestring.refresh() RETURNS trigger AS - $BODY$ - BEGIN --- RAISE NOTICE 'Refresh waterway_linestring %', NEW.osm_id; +$$ +BEGIN + -- RAISE NOTICE 'Refresh waterway_linestring %', NEW.osm_id; NEW.tags = update_tags(NEW.tags, NEW.geometry); RETURN NEW; - END; - $BODY$ -language plpgsql; +END; +$$ LANGUAGE plpgsql; CREATE TRIGGER trigger_refresh - BEFORE INSERT OR UPDATE ON osm_waterway_linestring + BEFORE INSERT OR UPDATE + ON osm_waterway_linestring FOR EACH ROW - EXECUTE PROCEDURE waterway_linestring.refresh(); +EXECUTE PROCEDURE waterway_linestring.refresh(); diff --git a/layers/waterway/waterway.sql b/layers/waterway/waterway.sql index 35c277f..57fb345 100644 --- a/layers/waterway/waterway.sql +++ b/layers/waterway/waterway.sql @@ -1,112 +1,224 @@ -CREATE OR REPLACE FUNCTION waterway_brunnel(is_bridge BOOL, is_tunnel BOOL) RETURNS TEXT AS $$ - SELECT CASE - WHEN is_bridge THEN 'bridge' - WHEN is_tunnel THEN 'tunnel' - END; +CREATE OR REPLACE FUNCTION waterway_brunnel(is_bridge bool, is_tunnel bool) RETURNS text AS $$ -LANGUAGE SQL -IMMUTABLE STRICT PARALLEL SAFE; +SELECT CASE + WHEN is_bridge THEN 'bridge' + WHEN is_tunnel THEN 'tunnel' + END; +$$ LANGUAGE SQL IMMUTABLE + STRICT + PARALLEL SAFE; -- etldoc: ne_110m_rivers_lake_centerlines -> waterway_z3 -CREATE OR REPLACE VIEW waterway_z3 AS ( - SELECT geometry, 'river'::text AS class, NULL::text AS name, NULL::text AS name_en, NULL::text AS name_de, NULL::hstore AS tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM ne_110m_rivers_lake_centerlines - WHERE featurecla = 'River' -); +CREATE OR REPLACE VIEW waterway_z3 AS +( +SELECT geometry, + 'river'::text AS class, + NULL::text AS name, + NULL::text AS name_en, + NULL::text AS name_de, + NULL::hstore AS tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM ne_110m_rivers_lake_centerlines +WHERE featurecla = 'River' + ); -- etldoc: ne_50m_rivers_lake_centerlines -> waterway_z4 -CREATE OR REPLACE VIEW waterway_z4 AS ( - SELECT geometry, 'river'::text AS class, NULL::text AS name, NULL::text AS name_en, NULL::text AS name_de, NULL::hstore AS tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM ne_50m_rivers_lake_centerlines - WHERE featurecla = 'River' -); +CREATE OR REPLACE VIEW waterway_z4 AS +( +SELECT geometry, + 'river'::text AS class, + NULL::text AS name, + NULL::text AS name_en, + NULL::text AS name_de, + NULL::hstore AS tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM ne_50m_rivers_lake_centerlines +WHERE featurecla = 'River' + ); -- etldoc: ne_10m_rivers_lake_centerlines -> waterway_z6 -CREATE OR REPLACE VIEW waterway_z6 AS ( - SELECT geometry, 'river'::text AS class, NULL::text AS name, NULL::text AS name_en, NULL::text AS name_de, NULL::hstore AS tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM ne_10m_rivers_lake_centerlines - WHERE featurecla = 'River' -); +CREATE OR REPLACE VIEW waterway_z6 AS +( +SELECT geometry, + 'river'::text AS class, + NULL::text AS name, + NULL::text AS name_en, + NULL::text AS name_de, + NULL::hstore AS tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM ne_10m_rivers_lake_centerlines +WHERE featurecla = 'River' + ); -- etldoc: osm_important_waterway_linestring_gen3 -> waterway_z9 -CREATE OR REPLACE VIEW waterway_z9 AS ( - SELECT geometry, 'river'::text AS class, name, name_en, name_de, tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM osm_important_waterway_linestring_gen3 -); +CREATE OR REPLACE VIEW waterway_z9 AS +( +SELECT geometry, + 'river'::text AS class, + name, + name_en, + name_de, + tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM osm_important_waterway_linestring_gen3 + ); -- etldoc: osm_important_waterway_linestring_gen2 -> waterway_z10 -CREATE OR REPLACE VIEW waterway_z10 AS ( - SELECT geometry, 'river'::text AS class, name, name_en, name_de, tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM osm_important_waterway_linestring_gen2 -); +CREATE OR REPLACE VIEW waterway_z10 AS +( +SELECT geometry, + 'river'::text AS class, + name, + name_en, + name_de, + tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM osm_important_waterway_linestring_gen2 + ); -- etldoc:osm_important_waterway_linestring_gen1 -> waterway_z11 -CREATE OR REPLACE VIEW waterway_z11 AS ( - SELECT geometry, 'river'::text AS class, name, name_en, name_de, tags, NULL::boolean AS is_bridge, NULL::boolean AS is_tunnel, NULL::boolean AS is_intermittent - FROM osm_important_waterway_linestring_gen1 -); +CREATE OR REPLACE VIEW waterway_z11 AS +( +SELECT geometry, + 'river'::text AS class, + name, + name_en, + name_de, + tags, + NULL::boolean AS is_bridge, + NULL::boolean AS is_tunnel, + NULL::boolean AS is_intermittent +FROM osm_important_waterway_linestring_gen1 + ); -- etldoc: osm_waterway_linestring -> waterway_z12 -CREATE OR REPLACE VIEW waterway_z12 AS ( - SELECT geometry, waterway::text AS class, name, name_en, name_de, tags, is_bridge, is_tunnel, is_intermittent - FROM osm_waterway_linestring - WHERE waterway IN ('river', 'canal') -); +CREATE OR REPLACE VIEW waterway_z12 AS +( +SELECT geometry, + waterway::text AS class, + name, + name_en, + name_de, + tags, + is_bridge, + is_tunnel, + is_intermittent +FROM osm_waterway_linestring +WHERE waterway IN ('river', 'canal') + ); -- etldoc: osm_waterway_linestring -> waterway_z13 -CREATE OR REPLACE VIEW waterway_z13 AS ( - SELECT geometry, waterway::text AS class, name, name_en, name_de, tags, is_bridge, is_tunnel, is_intermittent - FROM osm_waterway_linestring - WHERE waterway IN ('river', 'canal', 'stream', 'drain', 'ditch') -); +CREATE OR REPLACE VIEW waterway_z13 AS +( +SELECT geometry, + waterway::text AS class, + name, + name_en, + name_de, + tags, + is_bridge, + is_tunnel, + is_intermittent +FROM osm_waterway_linestring +WHERE waterway IN ('river', 'canal', 'stream', 'drain', 'ditch') + ); -- etldoc: osm_waterway_linestring -> waterway_z14 -CREATE OR REPLACE VIEW waterway_z14 AS ( - SELECT geometry, waterway::text AS class, name, name_en, name_de, tags, is_bridge, is_tunnel, is_intermittent - FROM osm_waterway_linestring -); +CREATE OR REPLACE VIEW waterway_z14 AS +( +SELECT geometry, + waterway::text AS class, + name, + name_en, + name_de, + tags, + is_bridge, + is_tunnel, + is_intermittent +FROM osm_waterway_linestring + ); -- etldoc: layer_waterway[shape=record fillcolor=lightpink, style="rounded,filled", -- etldoc: label="layer_waterway | z3 | z4-z5 | z6-8 | z9 | z10 | z11 | z12| z13| z14+" ]; CREATE OR REPLACE FUNCTION layer_waterway(bbox geometry, zoom_level int) -RETURNS TABLE(geometry geometry, class text, name text, name_en text, name_de text, brunnel text, intermittent int, tags hstore) AS $$ - SELECT geometry, class, - NULLIF(name, '') AS name, - COALESCE(NULLIF(name_en, ''), name) AS name_en, - COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, - waterway_brunnel(is_bridge, is_tunnel) AS brunnel, - is_intermittent::int AS intermittent, - tags - FROM ( - -- etldoc: waterway_z3 -> layer_waterway:z3 - SELECT * FROM waterway_z3 WHERE zoom_level = 3 - UNION ALL - -- etldoc: waterway_z4 -> layer_waterway:z4_5 - SELECT * FROM waterway_z4 WHERE zoom_level BETWEEN 4 AND 5 - UNION ALL - -- etldoc: waterway_z6 -> layer_waterway:z6_8 - SELECT * FROM waterway_z6 WHERE zoom_level BETWEEN 6 AND 8 - UNION ALL - -- etldoc: waterway_z9 -> layer_waterway:z9 - SELECT * FROM waterway_z9 WHERE zoom_level = 9 - UNION ALL - -- etldoc: waterway_z10 -> layer_waterway:z10 - SELECT * FROM waterway_z10 WHERE zoom_level = 10 - UNION ALL - -- etldoc: waterway_z11 -> layer_waterway:z11 - SELECT * FROM waterway_z11 WHERE zoom_level = 11 - UNION ALL - -- etldoc: waterway_z12 -> layer_waterway:z12 - SELECT * FROM waterway_z12 WHERE zoom_level = 12 - UNION ALL - -- etldoc: waterway_z13 -> layer_waterway:z13 - SELECT * FROM waterway_z13 WHERE zoom_level = 13 - UNION ALL - -- etldoc: waterway_z14 -> layer_waterway:z14 - SELECT * FROM waterway_z14 WHERE zoom_level >= 14 - ) AS zoom_levels - WHERE geometry && bbox; + RETURNS TABLE + ( + geometry geometry, + class text, + name text, + name_en text, + name_de text, + brunnel text, + intermittent int, + tags hstore + ) +AS $$ -LANGUAGE SQL -IMMUTABLE PARALLEL SAFE; +SELECT geometry, + class, + NULLIF(name, '') AS name, + COALESCE(NULLIF(name_en, ''), name) AS name_en, + COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, + waterway_brunnel(is_bridge, is_tunnel) AS brunnel, + is_intermittent::int AS intermittent, + tags +FROM ( + -- etldoc: waterway_z3 -> layer_waterway:z3 + SELECT * + FROM waterway_z3 + WHERE zoom_level = 3 + UNION ALL + -- etldoc: waterway_z4 -> layer_waterway:z4_5 + SELECT * + FROM waterway_z4 + WHERE zoom_level BETWEEN 4 AND 5 + UNION ALL + -- etldoc: waterway_z6 -> layer_waterway:z6_8 + SELECT * + FROM waterway_z6 + WHERE zoom_level BETWEEN 6 AND 8 + UNION ALL + -- etldoc: waterway_z9 -> layer_waterway:z9 + SELECT * + FROM waterway_z9 + WHERE zoom_level = 9 + UNION ALL + -- etldoc: waterway_z10 -> layer_waterway:z10 + SELECT * + FROM waterway_z10 + WHERE zoom_level = 10 + UNION ALL + -- etldoc: waterway_z11 -> layer_waterway:z11 + SELECT * + FROM waterway_z11 + WHERE zoom_level = 11 + UNION ALL + -- etldoc: waterway_z12 -> layer_waterway:z12 + SELECT * + FROM waterway_z12 + WHERE zoom_level = 12 + UNION ALL + -- etldoc: waterway_z13 -> layer_waterway:z13 + SELECT * + FROM waterway_z13 + WHERE zoom_level = 13 + UNION ALL + -- etldoc: waterway_z14 -> layer_waterway:z14 + SELECT * + FROM waterway_z14 + WHERE zoom_level >= 14 + ) AS zoom_levels +WHERE geometry && bbox; +$$ LANGUAGE SQL IMMUTABLE + PARALLEL SAFE; From 60a3e1ea707f87316d9449a579e00845097b35b5 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 8 Jun 2020 12:26:11 -0400 Subject: [PATCH 09/20] Fix Makefile duplicate runs (#923) Make sure that core targets (i.e. part of the `all` target like build-sql and build yaml files) do not run multiple times if they already exist. Makefile for some reason does not like it when a real target depends on a PHONY target, and re-runs it. I added an `if` statement to skip building targets if their result already exists. --- Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fff3e29..ff4997e 100644 --- a/Makefile +++ b/Makefile @@ -192,24 +192,31 @@ help: .PHONY: init-dirs init-dirs: - @mkdir -p build/sql + @mkdir -p build/sql/parallel + @mkdir -p build/openmaptiles.tm2source @mkdir -p data/borders @mkdir -p cache build/openmaptiles.tm2source/data.yml: init-dirs - mkdir -p build/openmaptiles.tm2source +ifeq (,$(wildcard build/openmaptiles.tm2source/data.yml)) $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools generate-tm2source openmaptiles.yaml --host="postgres" --port=5432 --database="openmaptiles" --user="openmaptiles" --password="openmaptiles" > $@ +endif build/mapping.yaml: init-dirs +ifeq (,$(wildcard build/mapping.yaml)) $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools generate-imposm3 openmaptiles.yaml > $@ +endif .PHONY: build-sql build-sql: init-dirs +ifeq (,$(wildcard build/sql/run_last.sql)) + @mkdir -p build/sql/parallel $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c \ 'generate-sql openmaptiles.yaml --dir ./build/sql \ && generate-sqltomvt openmaptiles.yaml \ --key --gzip --postgis-ver 3.0.1 \ - --function --fname=getmvt >> "./build/sql/run_last.sql"' + --function --fname=getmvt >> ./build/sql/run_last.sql' +endif .PHONY: clean clean: From 0b1511d60d633089be88cefbf0ad91c407e97684 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 8 Jun 2020 12:32:09 -0400 Subject: [PATCH 10/20] NOOP water - Move updating sql into separate file (#920) Use `update_water.sql` for all queries that update db to be consistent with the other layers. --- layers/water/update_water.sql | 78 +++++++++++++++++++++++++++++++++ layers/water/water.sql | 81 ----------------------------------- layers/water/water.yaml | 1 + 3 files changed, 79 insertions(+), 81 deletions(-) create mode 100644 layers/water/update_water.sql diff --git a/layers/water/update_water.sql b/layers/water/update_water.sql new file mode 100644 index 0000000..9094fc5 --- /dev/null +++ b/layers/water/update_water.sql @@ -0,0 +1,78 @@ +-- This statement can be deleted after the water importer image stops creating this object as a table +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen1 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + +-- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen1 +DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen1 CASCADE; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen1 AS +( +SELECT ST_Simplify(geometry, 20) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen1_idx ON osm_ocean_polygon_gen1 USING gist (geometry); + + +-- This statement can be deleted after the water importer image stops creating this object as a table +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen2 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + +-- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen2 +DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen2 CASCADE; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen2 AS +( +SELECT ST_Simplify(geometry, 40) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen2_idx ON osm_ocean_polygon_gen2 USING gist (geometry); + + +-- This statement can be deleted after the water importer image stops creating this object as a table +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen3 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + +-- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen3 +DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen3 CASCADE; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen3 AS +( +SELECT ST_Simplify(geometry, 80) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen3_idx ON osm_ocean_polygon_gen3 USING gist (geometry); + + +-- This statement can be deleted after the water importer image stops creating this object as a table +DO +$$ + BEGIN + DROP TABLE IF EXISTS osm_ocean_polygon_gen4 CASCADE; + EXCEPTION + WHEN wrong_object_type THEN + END; +$$ LANGUAGE plpgsql; + +-- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen4 +DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen4 CASCADE; +CREATE MATERIALIZED VIEW osm_ocean_polygon_gen4 AS +( +SELECT ST_Simplify(geometry, 160) AS geometry +FROM osm_ocean_polygon + ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; +CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen4_idx ON osm_ocean_polygon_gen4 USING gist (geometry); diff --git a/layers/water/water.sql b/layers/water/water.sql index 391ac2a..e59200b 100644 --- a/layers/water/water.sql +++ b/layers/water/water.sql @@ -1,84 +1,3 @@ --- This statement can be deleted after the water importer image stops creating this object as a table -DO -$$ - BEGIN - DROP TABLE IF EXISTS osm_ocean_polygon_gen1 CASCADE; - EXCEPTION - WHEN wrong_object_type THEN - END; -$$ LANGUAGE plpgsql; - --- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen1 -DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen1 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen1 AS -( -SELECT ST_Simplify(geometry, 20) AS geometry -FROM osm_ocean_polygon - ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; -CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen1_idx ON osm_ocean_polygon_gen1 USING gist (geometry); - - --- This statement can be deleted after the water importer image stops creating this object as a table -DO -$$ - BEGIN - DROP TABLE IF EXISTS osm_ocean_polygon_gen2 CASCADE; - EXCEPTION - WHEN wrong_object_type THEN - END; -$$ LANGUAGE plpgsql; - --- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen2 -DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen2 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen2 AS -( -SELECT ST_Simplify(geometry, 40) AS geometry -FROM osm_ocean_polygon - ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; -CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen2_idx ON osm_ocean_polygon_gen2 USING gist (geometry); - - --- This statement can be deleted after the water importer image stops creating this object as a table -DO -$$ - BEGIN - DROP TABLE IF EXISTS osm_ocean_polygon_gen3 CASCADE; - EXCEPTION - WHEN wrong_object_type THEN - END; -$$ LANGUAGE plpgsql; - --- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen3 -DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen3 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen3 AS -( -SELECT ST_Simplify(geometry, 80) AS geometry -FROM osm_ocean_polygon - ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; -CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen3_idx ON osm_ocean_polygon_gen3 USING gist (geometry); - - --- This statement can be deleted after the water importer image stops creating this object as a table -DO -$$ - BEGIN - DROP TABLE IF EXISTS osm_ocean_polygon_gen4 CASCADE; - EXCEPTION - WHEN wrong_object_type THEN - END; -$$ LANGUAGE plpgsql; - --- etldoc: osm_ocean_polygon -> osm_ocean_polygon_gen4 -DROP MATERIALIZED VIEW IF EXISTS osm_ocean_polygon_gen4 CASCADE; -CREATE MATERIALIZED VIEW osm_ocean_polygon_gen4 AS -( -SELECT ST_Simplify(geometry, 160) AS geometry -FROM osm_ocean_polygon - ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; -CREATE INDEX IF NOT EXISTS osm_ocean_polygon_gen4_idx ON osm_ocean_polygon_gen4 USING gist (geometry); - - - CREATE OR REPLACE FUNCTION water_class(waterway text) RETURNS text AS $$ SELECT CASE diff --git a/layers/water/water.yaml b/layers/water/water.yaml index 24ecabe..cbd0a07 100644 --- a/layers/water/water.yaml +++ b/layers/water/water.yaml @@ -34,6 +34,7 @@ layer: datasource: query: (SELECT geometry, class, intermittent, brunnel FROM layer_water(!bbox!, z(!scale_denominator!))) AS t schema: + - ./update_water.sql - ./water.sql datasources: - type: imposm3 From ffd237d5c868b98a6cf9848c47c1e9b6398066ae Mon Sep 17 00:00:00 2001 From: zstadler Date: Mon, 8 Jun 2020 19:40:04 +0300 Subject: [PATCH 11/20] Fix `clean-unnecessary-docker` make target (#921) Add missing `-q` flag --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ff4997e..9045ebd 100644 --- a/Makefile +++ b/Makefile @@ -482,7 +482,7 @@ remove-docker-images: .PHONY: clean-unnecessary-docker clean-unnecessary-docker: @echo "Deleting unnecessary container(s)..." - @docker ps -a --filter "status=exited" | $(XARGS) docker rm + @docker ps -a -q --filter "status=exited" | $(XARGS) docker rm @echo "Deleting unnecessary image(s)..." @docker images | grep \ | awk -F" " '{print $$3}' | $(XARGS) docker rmi From 5e65ac8c521e122d8634f666358b9ad51a49749c Mon Sep 17 00:00:00 2001 From: zstadler Date: Tue, 9 Jun 2020 11:53:18 +0300 Subject: [PATCH 12/20] Add area-base filtering for park names in lower zoom levels (#911) Resolve https://github.com/openmaptiles/openmaptiles/issues/776 Thanks @zstadler for this PR. --- layers/park/layer.sql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/layers/park/layer.sql b/layers/park/layer.sql index 71157b9..bf2929a 100644 --- a/layers/park/layer.sql +++ b/layers/park/layer.sql @@ -198,6 +198,7 @@ FROM ( FROM osm_park_polygon_gen8 WHERE zoom_level = 6 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen7 -> layer_park:z7 @@ -214,6 +215,7 @@ FROM ( FROM osm_park_polygon_gen7 WHERE zoom_level = 7 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen6 -> layer_park:z8 @@ -230,6 +232,7 @@ FROM ( FROM osm_park_polygon_gen6 WHERE zoom_level = 8 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen5 -> layer_park:z9 @@ -246,6 +249,7 @@ FROM ( FROM osm_park_polygon_gen5 WHERE zoom_level = 9 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen4 -> layer_park:z10 @@ -262,6 +266,7 @@ FROM ( FROM osm_park_polygon_gen4 WHERE zoom_level = 10 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen3 -> layer_park:z11 @@ -278,6 +283,7 @@ FROM ( FROM osm_park_polygon_gen3 WHERE zoom_level = 11 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen2 -> layer_park:z12 @@ -294,6 +300,7 @@ FROM ( FROM osm_park_polygon_gen2 WHERE zoom_level = 12 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon_gen1 -> layer_park:z13 @@ -310,6 +317,7 @@ FROM ( FROM osm_park_polygon_gen1 WHERE zoom_level = 13 AND geometry_point && bbox + AND area > 70000*2^(20-zoom_level) UNION ALL -- etldoc: osm_park_polygon -> layer_park:z14 From 491bb10bd78e6c555c1948b2157780522b88dc41 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 9 Jun 2020 09:53:02 -0400 Subject: [PATCH 13/20] Expose MAX_PARALLEL_PSQL to users (#927) Allow users to override how many import-sql files are loaded in parallel at the same time. This change should be a noop --- .env | 3 +++ docker-compose.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.env b/.env index f6cb692..36f79f5 100644 --- a/.env +++ b/.env @@ -38,3 +38,6 @@ IMPOSM_CONFIG_FILE=/usr/src/app/config/repl_config.json BORDERS_CLEANUP_FILE=data/borders/cleanup.pbf BORDERS_PBF_FILE=data/borders/filtered.pbf BORDERS_CSV_FILE=data/borders/lines.csv + +# Number of parallel processes to use when importing sql files +MAX_PARALLEL_PSQL=5 diff --git a/docker-compose.yml b/docker-compose.yml index f586e1c..b01c663 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,6 +40,8 @@ services: BORDERS_CLEANUP_FILE: ${BORDERS_CLEANUP_FILE} BORDERS_PBF_FILE: ${BORDERS_PBF_FILE} BORDERS_CSV_FILE: ${BORDERS_CSV_FILE} + # Control import-sql processes + MAX_PARALLEL_PSQL: ${MAX_PARALLEL_PSQL} networks: - postgres_conn volumes: From 447a8380e0435dcef729c32ee0eb76d3ea648c8e Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 9 Jun 2020 10:00:10 -0400 Subject: [PATCH 14/20] Fix incorrect Imposm config updates (#922) * Current code incorrectly passes `IMPOSM_CONFIG_FILE` to the `generate-tiles` image, but should pass it to the tools. * add a test to ensure imposm config exists * add a test to ensure area is set during updates --- Makefile | 45 ++++++++++++++++++++++++++++++++++----------- docker-compose.yml | 4 ++-- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 9045ebd..cacf322 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,9 @@ SHELL = /bin/bash .SHELLFLAGS = -o pipefail -c +# Make all .env variables available for make targets +include .env + # Options to run with docker and docker-compose - ensure the container is destroyed on exit # Containers run as the current user rather than root (so that created files are not root-owned) DC_OPTS ?= --rm -u $(shell id -u):$(shell id -g) @@ -113,8 +116,12 @@ export BORDERS_CSV_FILE ?= data/borders/$(area).lines.csv export MBTILES_FILE ?= $(area).mbtiles MBTILES_LOCAL_FILE = data/$(MBTILES_FILE) -# Location of the dynamically-generated imposm config file -export IMPOSM_CONFIG_FILE ?= data/$(area).repl.json +ifeq ($(strip $(DIFF_MODE)),true) + # import-osm implementation requires IMPOSM_CONFIG_FILE to be set to a valid file + # For static (no-updates) import, we don't need to override the default value + # For the update mode, set location of the dynamically-generated area-based config file + export IMPOSM_CONFIG_FILE = data/$(area).repl.json +endif # download-osm generates this file with metadata about the file AREA_DC_CONFIG_FILE ?= data/$(area).dc-config.yml @@ -274,19 +281,33 @@ ifneq ($(strip $(url)),) $(if $(OSM_SERVER),$(error url parameter can only be used with non-specific download target:$(newline) make download area=$(area) url="$(url)"$(newline))) endif ifeq (,$(wildcard $(PBF_FILE))) - @echo "Downloading $(DOWNLOAD_AREA) into $(PBF_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" - @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools bash -c ' \ - if [[ "$$DIFF_MODE" == "true" ]]; then \ - download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ + ifeq ($(strip $(DIFF_MODE)),true) + @echo "Downloading $(DOWNLOAD_AREA) with replication support into $(PBF_FILE) and $(IMPOSM_CONFIG_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" + @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ --imposm-cfg "$(IMPOSM_CONFIG_FILE)" \ - --output "$(PBF_FILE)" ; \ - else \ - download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ - --output "$(PBF_FILE)" ; \ - fi' + --output "$(PBF_FILE)" + else + @echo "Downloading $(DOWNLOAD_AREA) into $(PBF_FILE) from $(if $(OSM_SERVER),$(OSM_SERVER),any source)" + @$(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools download-osm $(OSM_SERVER) "$(DOWNLOAD_AREA)" \ + --output "$(PBF_FILE)" + endif @echo "" else + ifeq ($(strip $(DIFF_MODE)),true) + ifeq (,$(wildcard $(IMPOSM_CONFIG_FILE))) + $(error \ + $(newline) Data files $(PBF_FILE) already exists, but $(IMPOSM_CONFIG_FILE) does not. \ + $(newline) You probably downloaded the data file before setting DIFF_MODE=true. \ + $(newline) You can delete the data file $(PBF_FILE) and re-run make download \ + $(newline) to re-download and generate config, or manually create $(IMPOSM_CONFIG_FILE) \ + $(newline) See example https://github.com/openmaptiles/openmaptiles-tools/blob/v5.2/bin/config/repl_config.json \ + $(newline)) + else + @echo "Data files $(PBF_FILE) and replication config $(IMPOSM_CONFIG_FILE) already exists, skipping the download." + endif + else @echo "Data files $(PBF_FILE) already exists, skipping the download." + endif endif .PHONY: generate-dc-config @@ -312,10 +333,12 @@ import-osm: all start-db-nowait .PHONY: update-osm update-osm: all start-db-nowait + @$(assert_area_is_given) $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-update' .PHONY: import-diff import-diff: all start-db-nowait + @$(assert_area_is_given) $(DOCKER_COMPOSE) run $(DC_OPTS) openmaptiles-tools sh -c 'pgwait && import-diff' .PHONY: import-data diff --git a/docker-compose.yml b/docker-compose.yml index b01c663..e2d4fc7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,8 @@ services: MAKE_DC_VERSION: "2.3" # Allow DIFF_MODE to be overwritten from shell DIFF_MODE: ${DIFF_MODE} + # Imposm configuration file describes how to load updates when enabled + IMPOSM_CONFIG_FILE: ${IMPOSM_CONFIG_FILE} # Which files to use during import-borders processing BORDERS_CLEANUP_FILE: ${BORDERS_CLEANUP_FILE} BORDERS_PBF_FILE: ${BORDERS_PBF_FILE} @@ -63,7 +65,6 @@ services: environment: FILTER_MAPNIK_OUTPUT: ${FILTER_MAPNIK_OUTPUT} MBTILES_NAME: ${MBTILES_FILE} - IMPOSM_CONFIG_FILE: ${IMPOSM_CONFIG_FILE} generate-vectortiles: image: "openmaptiles/generate-vectortiles:${TOOLS_VERSION}" @@ -76,7 +77,6 @@ services: environment: FILTER_MAPNIK_OUTPUT: ${FILTER_MAPNIK_OUTPUT} MBTILES_NAME: ${MBTILES_FILE} - IMPOSM_CONFIG_FILE: ${IMPOSM_CONFIG_FILE} BBOX: ${BBOX} MIN_ZOOM: ${MIN_ZOOM} MAX_ZOOM: ${MAX_ZOOM} From f889853cb6472e61756babf3ddaa588665daf519 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 11 Jun 2020 14:24:55 -0400 Subject: [PATCH 15/20] aerodrome_label: Remove unused function parameter (#919) Minor optimization - in function `layer_aerodrome_label(bbox, zoom_level, pixel_width)` last parameter is not being used, so removing. --- layers/aerodrome_label/aerodrome_label.yaml | 2 +- layers/aerodrome_label/layer.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/layers/aerodrome_label/aerodrome_label.yaml b/layers/aerodrome_label/aerodrome_label.yaml index 0a775c0..d165ff6 100644 --- a/layers/aerodrome_label/aerodrome_label.yaml +++ b/layers/aerodrome_label/aerodrome_label.yaml @@ -41,7 +41,7 @@ layer: key_field: osm_id key_field_as_attribute: no srid: 900913 - query: (SELECT osm_id, geometry, name, name_en, name_de, {name_languages}, class, iata, icao, ele, ele_ft FROM layer_aerodrome_label (!bbox!, z(!scale_denominator!), !pixel_width!)) AS t + query: (SELECT osm_id, geometry, name, name_en, name_de, {name_languages}, class, iata, icao, ele, ele_ft FROM layer_aerodrome_label(!bbox!, z(!scale_denominator!))) AS t schema: - ./update_aerodrome_label_point.sql - ./layer.sql diff --git a/layers/aerodrome_label/layer.sql b/layers/aerodrome_label/layer.sql index fd49267..242a0d9 100644 --- a/layers/aerodrome_label/layer.sql +++ b/layers/aerodrome_label/layer.sql @@ -1,8 +1,8 @@ + -- etldoc: layer_aerodrome_label[shape=record fillcolor=lightpink, style="rounded,filled", label="layer_aerodrome_label | z10+" ] ; CREATE OR REPLACE FUNCTION layer_aerodrome_label(bbox geometry, - zoom_level integer, - pixel_width numeric) + zoom_level integer) RETURNS TABLE ( osm_id bigint, From 8f3165556439646cc74e6b03322caf954c25dc20 Mon Sep 17 00:00:00 2001 From: Tomas Pohanka Date: Fri, 12 Jun 2020 11:04:33 +0200 Subject: [PATCH 16/20] Change GitHub Actions to dedicated server (#929) * Change GitHub Action to the dedicated server Ralph * bugfix - let quickstart generate-tiles up to zoom 14 --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0b896b8..af84a4d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,6 +23,9 @@ jobs: MIN_ZOOM: 0 MAX_ZOOM: 14 run: | + # For now, change the quickstart values directly in the .env file + # TODO: We should probably use env vars instead + sed -i 's/MAX_ZOOM=7/MAX_ZOOM=14/g' .env export QUIET=1 ./quickstart.sh $area @@ -39,7 +42,7 @@ jobs: performance: name: Evaluate performance - runs-on: ubuntu-latest + runs-on: self-hosted # Even though we technically don't need to wait for integrity test to finish, # there is no point to run long perf test until we know the code is OK needs: integrity_test From ad8bd415671358be764ae2f9829f56317ab14fe0 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sun, 14 Jun 2020 11:02:44 -0400 Subject: [PATCH 17/20] Do not wait for integrity test (#934) It's ok if integrity test fails -- makes the whole testing process faster by 10 minutes at a cost of some extra CPU cycles. --- .github/workflows/tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index af84a4d..1828869 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,9 +43,6 @@ jobs: performance: name: Evaluate performance runs-on: self-hosted - # Even though we technically don't need to wait for integrity test to finish, - # there is no point to run long perf test until we know the code is OK - needs: integrity_test env: ## Smaller tests (runs everything in about 30 minutes) ## Two test areas: equatorial-guinea and liechtenstein From 2b95d1cffabb10cd65f2e11b54c89535069f6e72 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Wed, 17 Jun 2020 12:15:26 -0400 Subject: [PATCH 18/20] Fix & optimize incorrect function declarations (#918) * All functions that access database must be declared as `STABLE`, not `IMMUTABLE` -- because database can change at any moment, e.g. during an update * there are a few functions that could be made `STRICT` -- passing `NULL` as a parameter will always result in a `NULL`, but for some reason that causes a significant decrease in perf. * tagged one function as parallel safe NOTE: somehow `ST_AsMVT()` method of tile generation is showing 70-90% slowdown with this patch. I am not sure of why this is happening. If the reason is the `IMMUTABLE` -> `STABLE` change, we may have to dig deeper into PG optimization --- layers/aerodrome_label/layer.sql | 3 ++- layers/aeroway/layer.sql | 3 ++- layers/boundary/boundary.sql | 8 ++++++-- layers/building/building.sql | 5 ++++- layers/housenumber/layer.sql | 3 ++- layers/landcover/landcover.sql | 4 +++- layers/landuse/landuse.sql | 3 ++- layers/mountain_peak/layer.sql | 3 ++- layers/park/layer.sql | 3 ++- layers/place/city.sql | 3 ++- layers/place/layer.sql | 3 ++- layers/poi/layer.sql | 3 ++- layers/transportation/layer.sql | 3 ++- layers/transportation_name/layer.sql | 3 ++- layers/water/water.sql | 3 ++- layers/water_name/layer.sql | 3 ++- layers/waterway/waterway.sql | 3 ++- 17 files changed, 41 insertions(+), 18 deletions(-) diff --git a/layers/aerodrome_label/layer.sql b/layers/aerodrome_label/layer.sql index 242a0d9..19b8b2a 100644 --- a/layers/aerodrome_label/layer.sql +++ b/layers/aerodrome_label/layer.sql @@ -38,5 +38,6 @@ SELECT FROM osm_aerodrome_label_point WHERE geometry && bbox AND zoom_level >= 10; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/aeroway/layer.sql b/layers/aeroway/layer.sql index 6863010..93f03fc 100644 --- a/layers/aeroway/layer.sql +++ b/layers/aeroway/layer.sql @@ -56,5 +56,6 @@ FROM ( WHERE zoom_level >= 14 ) AS zoom_levels WHERE geometry && bbox; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/boundary/boundary.sql b/layers/boundary/boundary.sql index bf75716..1100759 100644 --- a/layers/boundary/boundary.sql +++ b/layers/boundary/boundary.sql @@ -206,7 +206,10 @@ SELECT CASE THEN replace(SUBSTRING(name, POSITION(' at ' IN name) + 4), ' ', '') ELSE replace(replace(name, ' ', ''), 'Extentof', '') END; -$$ LANGUAGE SQL IMMUTABLE; +$$ LANGUAGE SQL IMMUTABLE + -- STRICT + PARALLEL SAFE + ; -- etldoc: ne_110m_admin_0_boundary_lines_land -> boundary_z0 @@ -625,5 +628,6 @@ FROM ( WHERE geometry && bbox AND zoom_level >= 13 ) AS zoom_levels; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/building/building.sql b/layers/building/building.sql index 85025d9..f08e863 100644 --- a/layers/building/building.sql +++ b/layers/building/building.sql @@ -112,6 +112,9 @@ FROM ( AND geometry && bbox ) AS zoom_levels ORDER BY render_height ASC, ST_YMin(geometry) DESC; -$$ LANGUAGE SQL IMMUTABLE; +$$ LANGUAGE SQL STABLE + -- STRICT + PARALLEL SAFE + ; -- not handled: where a building outline covers building parts diff --git a/layers/housenumber/layer.sql b/layers/housenumber/layer.sql index 2cf0b55..84cb4d8 100644 --- a/layers/housenumber/layer.sql +++ b/layers/housenumber/layer.sql @@ -18,5 +18,6 @@ SELECT FROM osm_housenumber_point WHERE zoom_level >= 14 AND geometry && bbox; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/landcover/landcover.sql b/layers/landcover/landcover.sql index e2e183f..35e4d59 100644 --- a/layers/landcover/landcover.sql +++ b/layers/landcover/landcover.sql @@ -15,6 +15,7 @@ SELECT CASE %%FIELD_MAPPING: class %% END; $$ LANGUAGE SQL IMMUTABLE + -- STRICT PARALLEL SAFE; -- etldoc: ne_110m_glaciated_areas -> landcover_z0 @@ -185,5 +186,6 @@ FROM ( WHERE zoom_level >= 14 AND geometry && bbox ) AS zoom_levels; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/landuse/landuse.sql b/layers/landuse/landuse.sql index 89233ae..a1cae13 100644 --- a/layers/landuse/landuse.sql +++ b/layers/landuse/landuse.sql @@ -214,5 +214,6 @@ FROM ( WHERE zoom_level >= 14 ) AS zoom_levels WHERE geometry && bbox; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/mountain_peak/layer.sql b/layers/mountain_peak/layer.sql index a104fac..9a9385a 100644 --- a/layers/mountain_peak/layer.sql +++ b/layers/mountain_peak/layer.sql @@ -57,5 +57,6 @@ WHERE zoom_level >= 7 AND (rank <= 5 OR zoom_level >= 14) ORDER BY "rank" ASC; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE PARALLEL SAFE; +-- TODO: Check if the above can be made STRICT -- i.e. if pixel_width could be NULL diff --git a/layers/park/layer.sql b/layers/park/layer.sql index bf2929a..e6547c8 100644 --- a/layers/park/layer.sql +++ b/layers/park/layer.sql @@ -336,5 +336,6 @@ FROM ( AND geometry_point && bbox ) AS park_point ) AS park_all; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE PARALLEL SAFE; +-- TODO: Check if the above can be made STRICT -- i.e. if pixel_width could be NULL diff --git a/layers/place/city.sql b/layers/place/city.sql index 4cc0b84..9c44e4f 100644 --- a/layers/place/city.sql +++ b/layers/place/city.sql @@ -74,5 +74,6 @@ FROM ( OR (zoom_level BETWEEN 11 AND 12 AND (gridrank <= 14 OR "rank" IS NOT NULL)) OR (zoom_level >= 13) ) AS city_all; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/place/layer.sql b/layers/place/layer.sql index 0dee27d..f4eae73 100644 --- a/layers/place/layer.sql +++ b/layers/place/layer.sql @@ -142,5 +142,6 @@ FROM ( FROM layer_city(bbox, zoom_level, pixel_width) ORDER BY "rank" ASC ) AS place_all -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE PARALLEL SAFE; +-- TODO: Check if the above can be made STRICT -- i.e. if pixel_width could be NULL diff --git a/layers/poi/layer.sql b/layers/poi/layer.sql index 6458aa4..a268bc6 100644 --- a/layers/poi/layer.sql +++ b/layers/poi/layer.sql @@ -94,5 +94,6 @@ FROM ( AND zoom_level >= 14 ) AS poi_union ORDER BY "rank" -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE PARALLEL SAFE; +-- TODO: Check if the above can be made STRICT -- i.e. if pixel_width could be NULL diff --git a/layers/transportation/layer.sql b/layers/transportation/layer.sql index e008b33..31966b3 100644 --- a/layers/transportation/layer.sql +++ b/layers/transportation/layer.sql @@ -698,5 +698,6 @@ FROM ( ) AS zoom_levels WHERE geometry && bbox ORDER BY z_order ASC; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/transportation_name/layer.sql b/layers/transportation_name/layer.sql index 9b0ea35..1d148f4 100644 --- a/layers/transportation_name/layer.sql +++ b/layers/transportation_name/layer.sql @@ -147,5 +147,6 @@ FROM ( ) AS zoom_levels WHERE geometry && bbox ORDER BY z_order ASC; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/water/water.sql b/layers/water/water.sql index e59200b..f218dd9 100644 --- a/layers/water/water.sql +++ b/layers/water/water.sql @@ -385,5 +385,6 @@ FROM ( WHERE zoom_level >= 14 ) AS zoom_levels WHERE geometry && bbox; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/water_name/layer.sql b/layers/water_name/layer.sql index 70a1d6b..2327a05 100644 --- a/layers/water_name/layer.sql +++ b/layers/water_name/layer.sql @@ -74,5 +74,6 @@ WHERE geometry && bbox OR (zoom_level >= "rank" AND "rank" IS NOT NULL) OR (zoom_level >= 8) ); -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; diff --git a/layers/waterway/waterway.sql b/layers/waterway/waterway.sql index 57fb345..36e5ca2 100644 --- a/layers/waterway/waterway.sql +++ b/layers/waterway/waterway.sql @@ -220,5 +220,6 @@ FROM ( WHERE zoom_level >= 14 ) AS zoom_levels WHERE geometry && bbox; -$$ LANGUAGE SQL IMMUTABLE +$$ LANGUAGE SQL STABLE + -- STRICT PARALLEL SAFE; From 6ac544fc9610b57fb3041eebd725211ec154885c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Rodrigo?= Date: Wed, 17 Jun 2020 19:58:12 +0200 Subject: [PATCH 19/20] Make update_osm_peak_point use incremental update #814 (#896) Thanks a lot @frodrigo. --- layers/mountain_peak/update_peak_point.sql | 54 ++++++---------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/layers/mountain_peak/update_peak_point.sql b/layers/mountain_peak/update_peak_point.sql index 8a08ba6..db0b3ae 100644 --- a/layers/mountain_peak/update_peak_point.sql +++ b/layers/mountain_peak/update_peak_point.sql @@ -1,57 +1,33 @@ -DROP TRIGGER IF EXISTS trigger_flag ON osm_peak_point; -DROP TRIGGER IF EXISTS trigger_refresh ON mountain_peak_point.updates; +DROP TRIGGER IF EXISTS trigger_update_point ON osm_peak_point; -- etldoc: osm_peak_point -> osm_peak_point -CREATE OR REPLACE FUNCTION update_osm_peak_point() RETURNS void AS +-- etldoc: osm_peak_point -> osm_peak_point +CREATE OR REPLACE FUNCTION update_osm_peak_point(new_osm_id bigint) RETURNS void AS $$ -BEGIN - UPDATE osm_peak_point - SET tags = update_tags(tags, geometry) - WHERE COALESCE(tags->'name:latin', tags->'name:nonlatin', tags->'name_int') IS NULL; +UPDATE osm_peak_point +SET tags = update_tags(tags, geometry) +WHERE (new_osm_id IS NULL OR osm_id = new_osm_id) + AND COALESCE(tags -> 'name:latin', tags -> 'name:nonlatin', tags -> 'name_int') IS NULL + AND tags != update_tags(tags, geometry) +$$ LANGUAGE SQL; -END; -$$ LANGUAGE plpgsql; - -SELECT update_osm_peak_point(); +SELECT update_osm_peak_point(NULL); -- Handle updates CREATE SCHEMA IF NOT EXISTS mountain_peak_point; -CREATE TABLE IF NOT EXISTS mountain_peak_point.updates -( - id serial PRIMARY KEY, - t text, - UNIQUE (t) -); -CREATE OR REPLACE FUNCTION mountain_peak_point.flag() RETURNS trigger AS +CREATE OR REPLACE FUNCTION mountain_peak_point.update() RETURNS trigger AS $$ BEGIN - INSERT INTO mountain_peak_point.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + PERFORM update_osm_peak_point(new.osm_id); RETURN NULL; END; $$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION mountain_peak_point.refresh() RETURNS trigger AS -$$ -BEGIN - RAISE LOG 'Refresh mountain_peak_point'; - PERFORM update_osm_peak_point(); - -- noinspection SqlWithoutWhere - DELETE FROM mountain_peak_point.updates; - RETURN NULL; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER trigger_flag - AFTER INSERT OR UPDATE OR DELETE +CREATE CONSTRAINT TRIGGER trigger_update_point + AFTER INSERT OR UPDATE ON osm_peak_point - FOR EACH STATEMENT -EXECUTE PROCEDURE mountain_peak_point.flag(); - -CREATE CONSTRAINT TRIGGER trigger_refresh - AFTER INSERT - ON mountain_peak_point.updates INITIALLY DEFERRED FOR EACH ROW -EXECUTE PROCEDURE mountain_peak_point.refresh(); +EXECUTE PROCEDURE mountain_peak_point.update(); From c86f4a557a489c7e79ad2aec98051c066ccf7ad7 Mon Sep 17 00:00:00 2001 From: Tomas Pohanka Date: Thu, 18 Jun 2020 14:01:06 +0200 Subject: [PATCH 20/20] Build aggregation on zoom level 13 (#936) * Building aggregation at zoom 13 --- layers/building/building.sql | 4 +- layers/building/building.yaml | 3 +- layers/building/etl_diagram.png | Bin 35798 -> 34584 bytes layers/building/mapping.yaml | 14 ++-- layers/building/update_building.sql | 125 ++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 layers/building/update_building.sql diff --git a/layers/building/building.sql b/layers/building/building.sql index f08e863..47b2c51 100644 --- a/layers/building/building.sql +++ b/layers/building/building.sql @@ -82,7 +82,7 @@ SELECT geometry, CASE WHEN hide_3d THEN TRUE END AS hide_3d FROM ( SELECT - -- etldoc: osm_building_polygon_gen1 -> layer_building:z13 + -- etldoc: osm_building_block_gen1 -> layer_building:z13 osm_id, geometry, NULL::int AS render_height, @@ -90,7 +90,7 @@ FROM ( NULL::text AS material, NULL::text AS colour, FALSE AS hide_3d - FROM osm_building_polygon_gen1 + FROM osm_building_block_gen1 WHERE zoom_level = 13 AND geometry && bbox UNION ALL diff --git a/layers/building/building.yaml b/layers/building/building.yaml index 1bf360b..ea2bc67 100644 --- a/layers/building/building.yaml +++ b/layers/building/building.yaml @@ -20,7 +20,8 @@ layer: hide_3d: | If True, building (part) should not be rendered in 3D. Currently, [building outlines](https://wiki.openstreetmap.org/wiki/Simple_3D_buildings) are marked as hide_3d. schema: + - ./update_building.sql - ./building.sql datasources: - type: imposm3 - mapping_file: ./mapping.yaml + mapping_file: ./mapping.yaml \ No newline at end of file diff --git a/layers/building/etl_diagram.png b/layers/building/etl_diagram.png index 53f5f042f58da244d6fc97a49a85a624b6008a13..c77cd48fb6a81d6f4911c1290dd9771ab98fbc2b 100644 GIT binary patch literal 34584 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 G&;J7|s|aTR literal 35798 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 Nnl{@YMt|9^{{=Y0$mIY4 diff --git a/layers/building/mapping.yaml b/layers/building/mapping.yaml index ce72b97..858899b 100644 --- a/layers/building/mapping.yaml +++ b/layers/building/mapping.yaml @@ -1,9 +1,9 @@ -generalized_tables: - # etldoc: imposm3 -> osm_building_polygon_gen1 - building_polygon_gen1: - source: building_polygon - sql_filter: area>power(ZRES12,2) AND ST_IsValid(geometry) - tolerance: ZRES14 +#generalized_tables: +# # etldoc: imposm3 -> osm_building_polygon_gen1 +# building_polygon_gen1: +# source: building_polygon +# sql_filter: area>power(ZRES12,2) AND ST_IsValid(geometry) +# tolerance: ZRES14 tables: # etldoc: imposm3 -> osm_building_polygon @@ -157,4 +157,4 @@ tables: type: member_type mapping: type: [building] - type: relation_member + type: relation_member \ No newline at end of file diff --git a/layers/building/update_building.sql b/layers/building/update_building.sql new file mode 100644 index 0000000..5c15ae8 --- /dev/null +++ b/layers/building/update_building.sql @@ -0,0 +1,125 @@ +DROP TRIGGER IF EXISTS trigger_refresh ON buildings.updates; +DROP TRIGGER IF EXISTS trigger_flag ON osm_building_polygon; + +--creating aggregated building blocks with removed small polygons and small +--holes. Aggregated polygons are simplified. + +--function returning recordset for matview +--returning recordset of buildings aggregates by zres 14, with removed small +--holes and with removed small buildings/blocks +-- + +CREATE OR REPLACE FUNCTION osm_building_block_gen1() + RETURNS table + ( + osm_id bigint, + geometry geometry + ) +AS +$$ +DECLARE + zres14 float := Zres(14); + zres12 float := Zres(12); +BEGIN + FOR osm_id, geometry IN + WITH dta AS ( -- CTE is used because of optimization + SELECT o.osm_id, o.geometry, ST_ClusterDBSCAN(o.geometry, eps := zres14, minpoints := 1) OVER () cid + FROM osm_building_polygon o + ) + SELECT (array_agg(dta.osm_id))[1] osm_id, + ST_Buffer(ST_MemUnion(ST_Buffer(dta.geometry, zres14, 'join=mitre')), -zres14, 'join=mitre') geometry + FROM dta + GROUP BY cid + + LOOP + -- removing holes smaller than + IF ST_NumInteriorRings(geometry) > 0 THEN -- only from geometries wih holes + geometry := ( + -- there are some multi-geometries in this layer + SELECT ST_Collect(gn) + FROM ( + -- in some cases are "holes" NULL, because all holes are smaller than + SELECT COALESCE( + -- exterior ring + ST_MakePolygon(ST_ExteriorRing(dmp.geom), holes), + ST_MakePolygon(ST_ExteriorRing(dmp.geom)) + ) gn + + FROM ST_Dump(geometry) dmp, -- 1 dump polygons + LATERAL ( + SELECT array_agg(ST_Boundary(rg.geom)) holes -- 2 create array + FROM ST_DumpRings(dmp.geom) rg -- 3 from rings + WHERE rg.path[1] > 0 -- 5 except inner ring + AND ST_Area(rg.geom) >= power(zres12, 2) -- 4 bigger than + ) holes + ) new_geom + ); + END IF; + + IF ST_Area(geometry) < power(zres12, 2) THEN + CONTINUE; + END IF; + + -- simplify + geometry := ST_SimplifyPreserveTopology(geometry, zres14::float); + + RETURN NEXT; + END LOOP; +END; +$$ LANGUAGE plpgsql STABLE + STRICT + PARALLEL SAFE; + + +DROP MATERIALIZED VIEW IF EXISTS osm_building_block_gen1; + +CREATE MATERIALIZED VIEW osm_building_block_gen1 AS +SELECT * +FROM osm_building_block_gen1(); + +CREATE INDEX ON osm_building_block_gen1 USING gist (geometry); +CREATE UNIQUE INDEX ON osm_building_block_gen1 USING btree (osm_id); + + +-- Handle updates + +CREATE SCHEMA IF NOT EXISTS buildings; + +CREATE TABLE IF NOT EXISTS buildings.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); + +CREATE OR REPLACE FUNCTION buildings.flag() RETURNS trigger AS +$$ +BEGIN + INSERT INTO buildings.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION buildings.refresh() RETURNS trigger AS +$$ +BEGIN + RAISE LOG 'Refresh buildings block'; + REFRESH MATERIALIZED VIEW osm_building_block_gen1; + -- noinspection SqlWithoutWhere + DELETE FROM buildings.updates; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_flag + AFTER INSERT OR UPDATE OR DELETE + ON osm_building_polygon + FOR EACH STATEMENT +EXECUTE PROCEDURE buildings.flag(); + +CREATE CONSTRAINT TRIGGER trigger_refresh + AFTER INSERT + ON buildings.updates + INITIALLY DEFERRED + FOR EACH ROW +EXECUTE PROCEDURE buildings.refresh(); \ No newline at end of file