Compare commits
84 Commits
0.0.2
...
0.2.0-serv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c768f6c44c | ||
|
|
1665cf8069 | ||
|
|
17ca4317f0 | ||
|
|
43b09da396 | ||
|
|
db715d6d54 | ||
|
|
6676b26250 | ||
|
|
7a0b927acd | ||
|
|
8176eee356 | ||
|
|
d1f61dadd4 | ||
|
|
1367c46957 | ||
|
|
b1a703d696 | ||
|
|
3960c13484 | ||
|
|
e7c58b9a51 | ||
|
|
731eb8c74f | ||
|
|
a5d6650e2f | ||
|
|
440dadb5e8 | ||
|
|
d34a6f2297 | ||
|
|
75c19c1c1b | ||
|
|
69a0665dd0 | ||
|
|
16bd866531 | ||
|
|
95a68f68d6 | ||
|
|
626d2bb1f4 | ||
|
|
4f68d28ee0 | ||
|
|
3f0ccefa41 | ||
|
|
8da211e77d | ||
|
|
56c8d26c87 | ||
|
|
5b729db139 | ||
|
|
8585d8ba51 | ||
|
|
23310dc024 | ||
|
|
179c3fea35 | ||
|
|
a147e76860 | ||
|
|
a7e83dab49 | ||
|
|
a1d6f79999 | ||
|
|
e73736cbec | ||
|
|
a00c2eac32 | ||
|
|
bb629dfe4b | ||
|
|
b417e8f1fc | ||
|
|
343bcf539a | ||
|
|
b4b1cd9592 | ||
|
|
2409d548b6 | ||
|
|
35b59c448f | ||
|
|
5309a6eae5 | ||
|
|
e4f327f890 | ||
|
|
593da7926a | ||
|
|
4e53397f1c | ||
|
|
90ba8c88d1 | ||
|
|
326c5e0f7d | ||
|
|
fffcef90a5 | ||
|
|
62ade7f1a0 | ||
|
|
1a8109ecdf | ||
|
|
63651f512b | ||
|
|
c129a8c82d | ||
|
|
d3d6147b8e | ||
|
|
e46600325b | ||
|
|
54b45c8076 | ||
|
|
c58d7229a2 | ||
|
|
bd4a343e93 | ||
|
|
7c7c3e726e | ||
|
|
97a918306f | ||
|
|
9062ff8b74 | ||
|
|
d9c016d242 | ||
|
|
ba7af1ca2c | ||
|
|
db3eaf31ad | ||
|
|
56a4c60c8f | ||
|
|
c0cef3dc80 | ||
|
|
7cce491a13 | ||
|
|
49941a78f3 | ||
|
|
4bffdb5de1 | ||
|
|
bd8ec71855 | ||
|
|
984519e7f1 | ||
|
|
c74947b0a5 | ||
|
|
aced68096b | ||
|
|
8a51558068 | ||
|
|
3488d3f990 | ||
|
|
111804dafc | ||
|
|
af051e2ed5 | ||
|
|
4d0cabb429 | ||
|
|
7c3ab87b78 | ||
|
|
ad9c16b4df | ||
|
|
fc35911b91 | ||
|
|
b2fa8739e2 | ||
|
|
a7371c0a48 | ||
|
|
6740ada16e | ||
|
|
9ecabf9144 |
19
README.md
19
README.md
@@ -1,2 +1,21 @@
|
||||
# geocoder-api
|
||||
The CartoDB Geocoder SQL API (server and client FTM)
|
||||
|
||||
### Deploy instructions
|
||||
Steps to deploy a new Geocoder API version :
|
||||
|
||||
- Deploy new version of geocoder API to all servers
|
||||
- Update the server user using: ALTER EXTENSION cdb_geocoder_server UPDATE TO '<CURRENT_VERSION>';
|
||||
- Update the python dependencies if needed: **cartodb_geocoder** and **heremaps**
|
||||
- Add the needed config in the `cdb_conf` table:
|
||||
- `redis_metadata_config` and `redis_metrics_conf`
|
||||
- `{"sentinel_host": "localhost", "sentinel_port": 26739, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}`
|
||||
- `heremaps_conf`
|
||||
- `{"app_id": "APP_ID", "app_code": "APP_CODE"}`
|
||||
- Deploy the client to all the servers with the new version
|
||||
- Deploy the editor with the new geocoder api version changed (https://github.com/CartoDB/cartodb/blob/master/app/models/user/db_service.rb#L18)
|
||||
- Execute the rails task to update first the CartoDB team organizaton to test in production
|
||||
- `RAILS_ENV=production bundle exec rake cartodb:db:configure_geocoder_extension_for_organizations['team']`
|
||||
- Check if all works perfectly for our team. If so, execute the rake tasks to update all the users and organizations:
|
||||
- `RAILS_ENV=production bundle exec rake cartodb:db:configure_geocoder_extension_for_organizations['', true]`
|
||||
- `RAILS_ENV=production bundle exec rake cartodb:db:configure_geocoder_extension_for_non_org_users['', true]`
|
||||
|
||||
4
client/.gitignore
vendored
4
client/.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
results/
|
||||
regression.diffs
|
||||
regression.out
|
||||
20_public_functions.sql
|
||||
30_plproxy_functions.sql
|
||||
90_grant_execute.sql
|
||||
cdb_geocoder_client--0.0.1.sql
|
||||
cdb_geocoder_client--0.1.0.sql
|
||||
|
||||
@@ -3,9 +3,22 @@
|
||||
EXTENSION = cdb_geocoder_client
|
||||
EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
|
||||
|
||||
DATA = $(EXTENSION)--$(EXTVERSION).sql
|
||||
# The new version to be generated from templates
|
||||
NEW_EXTENSION_ARTIFACT = $(EXTENSION)--$(EXTVERSION).sql
|
||||
|
||||
REGRESS = $(notdir $(basename $(wildcard sql/*test.sql)))
|
||||
# DATA is a special variable used by postgres build infrastructure
|
||||
# These are the files to be installed in the server shared dir,
|
||||
# for installation from scratch, upgrades and downgrades.
|
||||
# @see http://www.postgresql.org/docs/current/static/extend-pgxs.html
|
||||
DATA = $(NEW_EXTENSION_ARTIFACT) \
|
||||
cdb_geocoder_client--0.0.1.sql \
|
||||
cdb_geocoder_client--0.1.0--0.0.1.sql \
|
||||
cdb_geocoder_client--0.0.1--0.1.0.sql
|
||||
|
||||
|
||||
REGRESS = $(notdir $(basename $(wildcard test/$(EXTVERSION)/sql/*test.sql)))
|
||||
TEST_DIR = test/$(EXTVERSION)
|
||||
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)'
|
||||
|
||||
# postgres build stuff
|
||||
PG_CONFIG = pg_config
|
||||
@@ -16,7 +29,7 @@ SOURCES_DATA_DIR = sql/$(EXTVERSION)
|
||||
|
||||
# The interface definition is used along with some templates to automatically generate code
|
||||
RENDERER = ../sql-template-renderer
|
||||
INTERFACE_FILE = ../interface.yaml
|
||||
INTERFACE_FILE = ../interface_$(EXTVERSION).yaml
|
||||
TEMPLATE_DIR = templates
|
||||
TEMPLATE_FILES = $(wildcard $(TEMPLATE_DIR)/*.erb)
|
||||
GENERATED_SQL_FILES = $(patsubst $(TEMPLATE_DIR)/%.erb, $(SOURCES_DATA_DIR)/%.sql, $(TEMPLATE_FILES))
|
||||
@@ -26,7 +39,7 @@ $(GENERATED_SQL_FILES): $(SOURCES_DATA_DIR)/%.sql: $(TEMPLATE_DIR)/%.erb $(INTER
|
||||
|
||||
SOURCES_DATA = $(wildcard $(SOURCES_DATA_DIR)/*.sql) $(GENERATED_SQL_FILES)
|
||||
|
||||
$(DATA): $(SOURCES_DATA)
|
||||
$(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA)
|
||||
rm -f $@
|
||||
cat $(SOURCES_DATA_DIR)/*.sql >> $@
|
||||
|
||||
@@ -34,5 +47,5 @@ all: $(DATA)
|
||||
|
||||
# Only meant for development time, do not use once a version is released
|
||||
devclean:
|
||||
rm -f $(DATA)
|
||||
rm -f $(NEW_EXTENSION_ARTIFACT)
|
||||
rm -f $(GENERATED_SQL_FILES)
|
||||
|
||||
60
client/cdb_geocoder_client--0.0.1--0.1.0.sql
Normal file
60
client/cdb_geocoder_client--0.0.1--0.1.0.sql
Normal file
@@ -0,0 +1,60 @@
|
||||
--
|
||||
-- Get entity config function
|
||||
--
|
||||
-- The purpose of this function is to retrieve the username and organization name from
|
||||
-- a) schema where he/her is the owner in case is an organization user
|
||||
-- b) entity_name from the cdb_conf database in case is a non organization user
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_entity_config()
|
||||
RETURNS record AS $$
|
||||
DECLARE
|
||||
result cdb_geocoder_client._entity_config;
|
||||
is_organization boolean;
|
||||
username text;
|
||||
organization_name text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'is_organization' INTO is_organization;
|
||||
IF is_organization IS NULL THEN
|
||||
RAISE EXCEPTION 'User must have user configuration in the config table';
|
||||
ELSIF is_organization = TRUE THEN
|
||||
SELECT nspname
|
||||
FROM pg_namespace s
|
||||
LEFT JOIN pg_roles r ON s.nspowner = r.oid
|
||||
WHERE r.rolname = session_user INTO username;
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO organization_name;
|
||||
ELSE
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO username;
|
||||
organization_name = NULL;
|
||||
END IF;
|
||||
result.username = username;
|
||||
result.organization_name = organization_name;
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_street_point (searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_street_point (username text, organization_name text, searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_street_point (username, organization_name, searchtext, city, state_province, country);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_street_point(searchtext text, city text, state_province text, country text) TO publicuser;
|
||||
359
client/cdb_geocoder_client--0.0.1.sql
Normal file
359
client/cdb_geocoder_client--0.0.1.sql
Normal file
@@ -0,0 +1,359 @@
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_client" to load this file. \quit
|
||||
--
|
||||
-- Geocoder server connection config
|
||||
--
|
||||
-- The purpose of this function is provide to the PL/Proxy functions
|
||||
-- the connection string needed to connect with the server
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._server_conn_str()
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
db_connection_str text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('geocoder_server_config')->'connection_str' INTO db_connection_str;
|
||||
SELECT trim(both '"' FROM db_connection_str) INTO db_connection_str;
|
||||
RETURN db_connection_str;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';CREATE TYPE cdb_geocoder_client._entity_config AS (
|
||||
username text,
|
||||
organization_name text
|
||||
);
|
||||
|
||||
--
|
||||
-- Get entity config function
|
||||
--
|
||||
-- The purpose of this function is to retrieve the username and organization name from
|
||||
-- a) schema where he/her is the owner in case is an organization user
|
||||
-- b) entity_name from the cdb_conf database in case is a non organization user
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_entity_config()
|
||||
RETURNS record AS $$
|
||||
DECLARE
|
||||
result cdb_geocoder_client._entity_config;
|
||||
is_organization boolean;
|
||||
username text;
|
||||
organization_name text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'is_organization' INTO is_organization;
|
||||
IF is_organization IS NULL THEN
|
||||
RAISE EXCEPTION 'User must have user configuration in the config table';
|
||||
ELSIF is_organization = TRUE THEN
|
||||
SELECT nspname
|
||||
FROM pg_namespace s
|
||||
LEFT JOIN pg_roles r ON s.nspowner = r.oid
|
||||
WHERE r.rolname = session_user INTO username;
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'entity_name' INTO organization_name;
|
||||
ELSE
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'entity_name' INTO username;
|
||||
organization_name = NULL;
|
||||
END IF;
|
||||
result.username = username;
|
||||
result.organization_name = organization_name;
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_admin0_polygon (country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_admin0_polygon(username, orgname, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_admin1_polygon (admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_admin1_polygon (admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point (city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point (city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point (city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, admin1_name, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_postalcode_polygon (postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_postalcode_polygon(username, orgname, postal_code, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_postalcode_point (postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_postalcode_point(username, orgname, postal_code, country_name) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
--
|
||||
-- Public geocoder API function
|
||||
--
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client.cdb_geocode_ipaddress_point (ip_address text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
username text;
|
||||
orgname text;
|
||||
BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM cdb_geocoder_client._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
END IF;
|
||||
SELECT cdb_geocoder_client._cdb_geocode_ipaddress_point(username, orgname, ip_address) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_admin0_polygon (username text, organization_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin0_polygon (username, organization_name, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_admin1_polygon (username text, organization_name text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon (username, organization_name, admin1_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_admin1_polygon (username text, organization_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon (username, organization_name, admin1_name, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point (username, organization_name, city_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point (username, organization_name, city_name, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point (username, organization_name, city_name, admin1_name, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_postalcode_polygon (username text, organization_name text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_postalcode_polygon (username, organization_name, postal_code, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_postalcode_point (username text, organization_name text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_postalcode_point (username, organization_name, postal_code, country_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_geocode_ipaddress_point (username text, organization_name text, ip_address text)
|
||||
RETURNS Geometry AS $$
|
||||
CONNECT cdb_geocoder_client._server_conn_str();
|
||||
SELECT cdb_geocoder_server.cdb_geocode_ipaddress_point (username, organization_name, ip_address);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
-- Make sure by default there are no permissions for publicuser
|
||||
-- NOTE: this happens at extension creation time, as part of an implicit transaction.
|
||||
REVOKE ALL PRIVILEGES ON SCHEMA cdb_geocoder_client FROM PUBLIC, publicuser CASCADE;
|
||||
|
||||
-- Grant permissions on the schema to publicuser (but just the schema)
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_client TO publicuser;
|
||||
|
||||
-- Revoke execute permissions on all functions in the schema by default
|
||||
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_client FROM PUBLIC, publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_admin0_polygon(country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_admin1_polygon(admin1_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_admin1_polygon(admin1_name text, country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point(city_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point(city_name text, country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_postalcode_polygon(postal_code text, country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_postalcode_point(postal_code text, country_name text) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.cdb_geocode_ipaddress_point(ip_address text) TO publicuser;
|
||||
38
client/cdb_geocoder_client--0.1.0--0.0.1.sql
Normal file
38
client/cdb_geocoder_client--0.1.0--0.0.1.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_client.cdb_geocode_street_point (text, text, text, text);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_client._cdb_geocode_street_point (text, text, text, text);
|
||||
-- This functions could exists due a first deploy with this name
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_client.cdb_geocode_street_point_v2 (text, text, text, text);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_client._cdb_geocode_street_point_v2 (text, text, text, text, text, text);
|
||||
|
||||
--
|
||||
-- Get entity config function
|
||||
--
|
||||
-- The purpose of this function is to retrieve the username and organization name from
|
||||
-- a) schema where he/her is the owner in case is an organization user
|
||||
-- b) entity_name from the cdb_conf database in case is a non organization user
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_entity_config()
|
||||
RETURNS record AS $$
|
||||
DECLARE
|
||||
result cdb_geocoder_client._entity_config;
|
||||
is_organization boolean;
|
||||
username text;
|
||||
organization_name text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'is_organization' INTO is_organization;
|
||||
IF is_organization IS NULL THEN
|
||||
RAISE EXCEPTION 'User must have user configuration in the config table';
|
||||
ELSIF is_organization = TRUE THEN
|
||||
SELECT nspname
|
||||
FROM pg_namespace s
|
||||
LEFT JOIN pg_roles r ON s.nspowner = r.oid
|
||||
WHERE r.rolname = session_user INTO username;
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'entity_name' INTO organization_name;
|
||||
ELSE
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'entity_name' INTO username;
|
||||
organization_name = NULL;
|
||||
END IF;
|
||||
result.username = username;
|
||||
result.organization_name = organization_name;
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
@@ -1,6 +1,6 @@
|
||||
# CartoDB geocoder client API extension
|
||||
comment = 'CartoDB geocoder client API extension'
|
||||
default_version = '0.0.1'
|
||||
default_version = '0.1.0'
|
||||
requires = 'plproxy, cartodb'
|
||||
superuser = true
|
||||
schema = cdb_geocoder_client
|
||||
|
||||
3
client/sql/0.0.1/.gitignore
vendored
3
client/sql/0.0.1/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
20_public_functions.sql
|
||||
30_plproxy_functions.sql
|
||||
90_grant_execute.sql
|
||||
@@ -1,2 +1,3 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_client" to load this file. \quit
|
||||
|
||||
3
client/sql/0.1.0/00_header.sql
Normal file
3
client/sql/0.1.0/00_header.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_client" to load this file. \quit
|
||||
16
client/sql/0.1.0/10_geocoder_server_conn.sql
Normal file
16
client/sql/0.1.0/10_geocoder_server_conn.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
--
|
||||
-- Geocoder server connection config
|
||||
--
|
||||
-- The purpose of this function is provide to the PL/Proxy functions
|
||||
-- the connection string needed to connect with the server
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._server_conn_str()
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
db_connection_str text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('geocoder_server_config')->'connection_str' INTO db_connection_str;
|
||||
SELECT trim(both '"' FROM db_connection_str) INTO db_connection_str;
|
||||
RETURN db_connection_str;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
37
client/sql/0.1.0/15_config_management.sql
Normal file
37
client/sql/0.1.0/15_config_management.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
CREATE TYPE cdb_geocoder_client._entity_config AS (
|
||||
username text,
|
||||
organization_name text
|
||||
);
|
||||
|
||||
--
|
||||
-- Get entity config function
|
||||
--
|
||||
-- The purpose of this function is to retrieve the username and organization name from
|
||||
-- a) schema where he/her is the owner in case is an organization user
|
||||
-- b) entity_name from the cdb_conf database in case is a non organization user
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_client._cdb_entity_config()
|
||||
RETURNS record AS $$
|
||||
DECLARE
|
||||
result cdb_geocoder_client._entity_config;
|
||||
is_organization boolean;
|
||||
username text;
|
||||
organization_name text;
|
||||
BEGIN
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->'is_organization' INTO is_organization;
|
||||
IF is_organization IS NULL THEN
|
||||
RAISE EXCEPTION 'User must have user configuration in the config table';
|
||||
ELSIF is_organization = TRUE THEN
|
||||
SELECT nspname
|
||||
FROM pg_namespace s
|
||||
LEFT JOIN pg_roles r ON s.nspowner = r.oid
|
||||
WHERE r.rolname = session_user INTO username;
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO organization_name;
|
||||
ELSE
|
||||
SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO username;
|
||||
organization_name = NULL;
|
||||
END IF;
|
||||
result.username = username;
|
||||
result.organization_name = organization_name;
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
9
client/sql/0.1.0/80_permissions.sql
Normal file
9
client/sql/0.1.0/80_permissions.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- Make sure by default there are no permissions for publicuser
|
||||
-- NOTE: this happens at extension creation time, as part of an implicit transaction.
|
||||
REVOKE ALL PRIVILEGES ON SCHEMA cdb_geocoder_client FROM PUBLIC, publicuser CASCADE;
|
||||
|
||||
-- Grant permissions on the schema to publicuser (but just the schema)
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_client TO publicuser;
|
||||
|
||||
-- Revoke execute permissions on all functions in the schema by default
|
||||
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_client FROM PUBLIC, publicuser;
|
||||
@@ -4,7 +4,7 @@
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>.<%= name %> (<%= params_with_type %>)
|
||||
CREATE OR REPLACE FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>.<%= name %> (<%= params_with_type_and_default %>)
|
||||
RETURNS <%= return_type %> AS $$
|
||||
DECLARE
|
||||
ret <%= return_type %>;
|
||||
@@ -14,7 +14,7 @@ BEGIN
|
||||
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||
RAISE EXCEPTION 'The api_key must be provided';
|
||||
END IF;
|
||||
SELECT u, o INTO username, orgname FROM _cdb_entity_config() AS (u text, o text);
|
||||
SELECT u, o INTO username, orgname FROM <%= GEOCODER_CLIENT_SCHEMA %>._cdb_entity_config() AS (u text, o text);
|
||||
-- JSON value stored "" is taken as literal
|
||||
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CREATE OR REPLACE FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>._<%= name %> (username text, organization_name text, <%= params_with_type %>)
|
||||
CREATE OR REPLACE FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>._<%= name %> (username text, organization_name text, <%= params_with_type_and_default %>)
|
||||
RETURNS <%= return_type %> AS $$
|
||||
CONNECT <%= GEOCODER_CLIENT_SCHEMA %>._server_conn_str();
|
||||
SELECT cdb_geocoder_server.<%= name %> (username, organization_name, <%= params %>);
|
||||
|
||||
29
client/test/0.1.0/expected/00_installation_test.out
Normal file
29
client/test/0.1.0/expected/00_installation_test.out
Normal file
@@ -0,0 +1,29 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION plproxy;
|
||||
-- Install the extension
|
||||
CREATE EXTENSION cdb_geocoder_client;
|
||||
-- Mock the server connection to point to this very test db
|
||||
SELECT cartodb.cdb_conf_setconf('geocoder_server_config', '{"connection_str": "dbname=contrib_regression host=127.0.0.1 user=postgres"}');
|
||||
cdb_conf_setconf
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Mock the user configuration
|
||||
SELECT cartodb.cdb_conf_setconf('user_config', '{"is_organization": false, "entity_name": "test_user"}');
|
||||
cdb_conf_setconf
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Mock the server schema
|
||||
CREATE SCHEMA cdb_geocoder_server;
|
||||
-- Create a test user to check permissions
|
||||
DROP ROLE IF EXISTS test_regular_user;
|
||||
CREATE ROLE test_regular_user;
|
||||
GRANT publicuser TO test_regular_user;
|
||||
ALTER ROLE test_regular_user SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
20
client/test/0.1.0/expected/10_admin0_test.out
Normal file
20
client/test/0.1.0/expected/10_admin0_test.out
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server function
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin0_polygon invoked with params (%, %, %)', username, orgname, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_admin0_polygon('Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin0_polygon(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin0_polygon invoked with params (test_user, <NULL>, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin0_polygon(username, orgname, country_name)"
|
||||
PL/pgSQL function cdb_geocode_admin0_polygon(text) line 15 at SQL statement
|
||||
cdb_geocode_admin0_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
36
client/test/0.1.0/expected/20_admin1_test.out
Normal file
36
client/test/0.1.0/expected/20_admin1_test.out
Normal file
@@ -0,0 +1,36 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (%, %, %)', username, orgname, admin1_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (%, %, %, %)', username, orgname, admin1_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_admin1_polygon('California');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin1_polygon(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (test_user, <NULL>, California)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name)"
|
||||
PL/pgSQL function cdb_geocode_admin1_polygon(text) line 15 at SQL statement
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_admin1_polygon('California', 'United States');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin1_polygon(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (test_user, <NULL>, California, United States)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_admin1_polygon(text,text) line 15 at SQL statement
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
52
client/test/0.1.0/expected/30_namedplaces_test.out
Normal file
52
client/test/0.1.0/expected/30_namedplaces_test.out
Normal file
@@ -0,0 +1,52 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %)', username, orgname, city_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %, %)', username, orgname, city_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %, %, %)', username, orgname, city_name, admin1_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_namedplace_point('Elx');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text,text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(5): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx, Valencia, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, admin1_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
36
client/test/0.1.0/expected/40_postalcodes_test.out
Normal file
36
client/test/0.1.0/expected/40_postalcodes_test.out
Normal file
@@ -0,0 +1,36 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_postalcode_polygon invoked with params (%, %, %, %)', username, orgname, postal_code, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_postalcode_point invoked with params (%, %, %, %)', username, orgname, postal_code, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_postalcode_polygon('03204', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_postalcode_polygon(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_postalcode_polygon invoked with params (test_user, <NULL>, 03204, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_postalcode_polygon(username, orgname, postal_code, country_name)"
|
||||
PL/pgSQL function cdb_geocode_postalcode_polygon(text,text) line 15 at SQL statement
|
||||
cdb_geocode_postalcode_polygon
|
||||
--------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_postalcode_point('03204', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_postalcode_point invoked with params (test_user, <NULL>, 03204, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_postalcode_point(username, orgname, postal_code, country_name)"
|
||||
PL/pgSQL function cdb_geocode_postalcode_point(text,text) line 15 at SQL statement
|
||||
cdb_geocode_postalcode_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
20
client/test/0.1.0/expected/50_ipaddresses_test.out
Normal file
20
client/test/0.1.0/expected/50_ipaddresses_test.out
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip_address text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_ipaddress_point invoked with params (%, %, %)', username, orgname, ip_address;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_ipaddress_point('8.8.8.8');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_ipaddress_point(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_ipaddress_point invoked with params (test_user, <NULL>, 8.8.8.8)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_ipaddress_point(username, orgname, ip_address)"
|
||||
PL/pgSQL function cdb_geocode_ipaddress_point(text) line 15 at SQL statement
|
||||
cdb_geocode_ipaddress_point
|
||||
-----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
101
client/test/0.1.0/expected/60_street_test.out
Normal file
101
client/test/0.1.0/expected/60_street_test.out
Normal file
@@ -0,0 +1,101 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point (username text, orgname text, searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (%, %, %, %, %, %)', username, orgname, searchtext, city, state_province, country;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_street_point('One street, 1');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, 1, <NULL>, <NULL>, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, <NULL>, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, state, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state', 'country');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, state, country)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', NULL, 'country');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, <NULL>, country)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street, 1');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, 1, <NULL>, <NULL>, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, <NULL>, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, state, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state', 'country');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, state, country)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('One street', 'city', NULL, 'country');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, One street, city, <NULL>, country)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
117
client/test/0.1.0/expected/90_permissions_test.out
Normal file
117
client/test/0.1.0/expected/90_permissions_test.out
Normal file
@@ -0,0 +1,117 @@
|
||||
-- Use regular user role
|
||||
SET ROLE test_regular_user;
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
-- Exercise the public function
|
||||
-- it is public, it shall work
|
||||
SELECT cdb_geocode_admin0_polygon('Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin0_polygon(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin0_polygon invoked with params (test_user, <NULL>, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin0_polygon(username, orgname, country_name)"
|
||||
PL/pgSQL function cdb_geocode_admin0_polygon(text) line 15 at SQL statement
|
||||
cdb_geocode_admin0_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_admin1_polygon('California');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin1_polygon(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (test_user, <NULL>, California)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name)"
|
||||
PL/pgSQL function cdb_geocode_admin1_polygon(text) line 15 at SQL statement
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_admin1_polygon('California', 'United States');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_admin1_polygon(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (test_user, <NULL>, California, United States)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_admin1_polygon(username, orgname, admin1_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_admin1_polygon(text,text) line 15 at SQL statement
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_namedplace_point('Elx');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx, Valencia)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text,text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_namedplace_point(5): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (test_user, <NULL>, Elx, Valencia, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_namedplace_point(username, orgname, city_name, admin1_name, country_name)"
|
||||
PL/pgSQL function cdb_geocode_namedplace_point(text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_postalcode_polygon('03204', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_postalcode_polygon(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_postalcode_polygon invoked with params (test_user, <NULL>, 03204, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_postalcode_polygon(username, orgname, postal_code, country_name)"
|
||||
PL/pgSQL function cdb_geocode_postalcode_polygon(text,text) line 15 at SQL statement
|
||||
cdb_geocode_postalcode_polygon
|
||||
--------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_postalcode_point('03204', 'Spain');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_postalcode_point invoked with params (test_user, <NULL>, 03204, Spain)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_postalcode_point(username, orgname, postal_code, country_name)"
|
||||
PL/pgSQL function cdb_geocode_postalcode_point(text,text) line 15 at SQL statement
|
||||
cdb_geocode_postalcode_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_ipaddress_point('8.8.8.8');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_ipaddress_point(3): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_ipaddress_point invoked with params (test_user, <NULL>, 8.8.8.8)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_ipaddress_point(username, orgname, ip_address)"
|
||||
PL/pgSQL function cdb_geocode_ipaddress_point(text) line 15 at SQL statement
|
||||
cdb_geocode_ipaddress_point
|
||||
-----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocode_street_point('one street, 1');
|
||||
NOTICE: cdb_geocoder_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (test_user, <NULL>, one street, 1, <NULL>, <NULL>, <NULL>)
|
||||
CONTEXT: SQL statement "SELECT cdb_geocoder_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
|
||||
PL/pgSQL function cdb_geocode_street_point(text,text,text,text) line 15 at SQL statement
|
||||
cdb_geocode_street_point
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Check the regular user has no permissions on private functions
|
||||
SELECT _cdb_geocode_admin0_polygon('evil_user', 'evil_orgname', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_admin0_polygon
|
||||
SELECT _cdb_geocode_admin1_polygon('evil_user', 'evil_orgname', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_admin1_polygon
|
||||
SELECT _cdb_geocode_admin1_polygon('evil_user', 'evil_orgname', 'Sheol', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_admin1_polygon
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol');
|
||||
ERROR: permission denied for function _cdb_geocode_namedplace_point
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_namedplace_point
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol', 'Hell', 'Ugly world');
|
||||
ERROR: permission denied for function _cdb_geocode_namedplace_point
|
||||
SELECT _cdb_geocode_postalcode_polygon('evil_user', 'evil_orgname', '66666', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_postalcode_polygon
|
||||
SELECT _cdb_geocode_postalcode_point('evil_user', 'evil_orgname', '66666', 'Hell');
|
||||
ERROR: permission denied for function _cdb_geocode_postalcode_point
|
||||
SELECT _cdb_geocode_ipaddress_point('evil_user', 'evil_orgname', '8.8.8.8');
|
||||
ERROR: permission denied for function _cdb_geocode_ipaddress_point
|
||||
SELECT _cdb_geocode_street_point('evil_user', 'evil_orgname', 'one street, 1');
|
||||
ERROR: permission denied for function _cdb_geocode_street_point
|
||||
23
client/test/0.1.0/sql/00_installation_test.sql
Normal file
23
client/test/0.1.0/sql/00_installation_test.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION plproxy;
|
||||
|
||||
-- Install the extension
|
||||
CREATE EXTENSION cdb_geocoder_client;
|
||||
|
||||
-- Mock the server connection to point to this very test db
|
||||
SELECT cartodb.cdb_conf_setconf('geocoder_server_config', '{"connection_str": "dbname=contrib_regression host=127.0.0.1 user=postgres"}');
|
||||
-- Mock the user configuration
|
||||
SELECT cartodb.cdb_conf_setconf('user_config', '{"is_organization": false, "entity_name": "test_user"}');
|
||||
|
||||
-- Mock the server schema
|
||||
CREATE SCHEMA cdb_geocoder_server;
|
||||
|
||||
-- Create a test user to check permissions
|
||||
DROP ROLE IF EXISTS test_regular_user;
|
||||
CREATE ROLE test_regular_user;
|
||||
GRANT publicuser TO test_regular_user;
|
||||
ALTER ROLE test_regular_user SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
15
client/test/0.1.0/sql/10_admin0_test.sql
Normal file
15
client/test/0.1.0/sql/10_admin0_test.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server function
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin0_polygon invoked with params (%, %, %)', username, orgname, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_admin0_polygon('Spain');
|
||||
24
client/test/0.1.0/sql/20_admin1_test.sql
Normal file
24
client/test/0.1.0/sql/20_admin1_test.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (%, %, %)', username, orgname, admin1_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_admin1_polygon invoked with params (%, %, %, %)', username, orgname, admin1_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_admin1_polygon('California');
|
||||
SELECT cdb_geocode_admin1_polygon('California', 'United States');
|
||||
33
client/test/0.1.0/sql/30_namedplaces_test.sql
Normal file
33
client/test/0.1.0/sql/30_namedplaces_test.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %)', username, orgname, city_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %, %)', username, orgname, city_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_namedplace_point invoked with params (%, %, %, %, %)', username, orgname, city_name, admin1_name, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_namedplace_point('Elx');
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Spain');
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia', 'Spain');
|
||||
|
||||
23
client/test/0.1.0/sql/40_postalcodes_test.sql
Normal file
23
client/test/0.1.0/sql/40_postalcodes_test.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_postalcode_polygon invoked with params (%, %, %, %)', username, orgname, postal_code, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, postal_code text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_postalcode_point invoked with params (%, %, %, %)', username, orgname, postal_code, country_name;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_postalcode_polygon('03204', 'Spain');
|
||||
SELECT cdb_geocode_postalcode_point('03204', 'Spain');
|
||||
15
client/test/0.1.0/sql/50_ipaddresses_test.sql
Normal file
15
client/test/0.1.0/sql/50_ipaddresses_test.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip_address text)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_ipaddress_point invoked with params (%, %, %)', username, orgname, ip_address;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_ipaddress_point('8.8.8.8');
|
||||
24
client/test/0.1.0/sql/60_street_test.sql
Normal file
24
client/test/0.1.0/sql/60_street_test.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Mock the server functions
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point (username text, orgname text, searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'cdb_geocoder_server.cdb_geocode_geocoder_street_point invoked with params (%, %, %, %, %, %)', username, orgname, searchtext, city, state_province, country;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
-- Exercise the public and the proxied function
|
||||
SELECT cdb_geocode_street_point('One street, 1');
|
||||
SELECT cdb_geocode_street_point('One street', 'city');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state', 'country');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', NULL, 'country');
|
||||
SELECT cdb_geocode_street_point('One street, 1');
|
||||
SELECT cdb_geocode_street_point('One street', 'city');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', 'state', 'country');
|
||||
SELECT cdb_geocode_street_point('One street', 'city', NULL, 'country');
|
||||
30
client/test/0.1.0/sql/90_permissions_test.sql
Normal file
30
client/test/0.1.0/sql/90_permissions_test.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
-- Use regular user role
|
||||
SET ROLE test_regular_user;
|
||||
|
||||
-- Add to the search path the schema
|
||||
SET search_path TO public,cartodb,cdb_geocoder_client;
|
||||
|
||||
-- Exercise the public function
|
||||
-- it is public, it shall work
|
||||
SELECT cdb_geocode_admin0_polygon('Spain');
|
||||
SELECT cdb_geocode_admin1_polygon('California');
|
||||
SELECT cdb_geocode_admin1_polygon('California', 'United States');
|
||||
SELECT cdb_geocode_namedplace_point('Elx');
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia');
|
||||
SELECT cdb_geocode_namedplace_point('Elx', 'Valencia', 'Spain');
|
||||
SELECT cdb_geocode_postalcode_polygon('03204', 'Spain');
|
||||
SELECT cdb_geocode_postalcode_point('03204', 'Spain');
|
||||
SELECT cdb_geocode_ipaddress_point('8.8.8.8');
|
||||
SELECT cdb_geocode_street_point('one street, 1');
|
||||
|
||||
-- Check the regular user has no permissions on private functions
|
||||
SELECT _cdb_geocode_admin0_polygon('evil_user', 'evil_orgname', 'Hell');
|
||||
SELECT _cdb_geocode_admin1_polygon('evil_user', 'evil_orgname', 'Hell');
|
||||
SELECT _cdb_geocode_admin1_polygon('evil_user', 'evil_orgname', 'Sheol', 'Hell');
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol');
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol', 'Hell');
|
||||
SELECT _cdb_geocode_namedplace_point('evil_user', 'evil_orgname', 'Sheol', 'Hell', 'Ugly world');
|
||||
SELECT _cdb_geocode_postalcode_polygon('evil_user', 'evil_orgname', '66666', 'Hell');
|
||||
SELECT _cdb_geocode_postalcode_point('evil_user', 'evil_orgname', '66666', 'Hell');
|
||||
SELECT _cdb_geocode_ipaddress_point('evil_user', 'evil_orgname', '8.8.8.8');
|
||||
SELECT _cdb_geocode_street_point('evil_user', 'evil_orgname', 'one street, 1');
|
||||
@@ -1,6 +1,6 @@
|
||||
# Geocoder API
|
||||
|
||||
The CartoDB Geocoder API allows you to match your data with geometries on your map. This geocoding service can be used programatically to geocode datasets via the CartoDB SQL API. It is fed from _Open Data_ and it serves geometries for countries, provinces, states, cities, postal codes and IP addresses.
|
||||
The CartoDB Geocoder API allows you to match your data with geometries on your map. This geocoding service can be used programatically to geocode datasets via the CartoDB SQL API. It is fed from _Open Data_ and it serves geometries for countries, provinces, states, cities, postal codes, IP addresses and street addresses.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@ Geometry (polygon, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_admin0_polygon('France')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
UPDATE {tablename} SET {the_geom} = cdb_geocode_admin0_polygon({country_column})
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_admin0_polygon({country_column})
|
||||
```
|
||||
|
||||
|
||||
@@ -54,14 +54,14 @@ Geometry (polygon, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
SELECT cdb_geocode_admin1_polygon('Alicante', 'Spain')
|
||||
```bash
|
||||
SELECT cdb_geocode_admin1_polygon('Alicante')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_admin1_polygon({province_column}, {country_column})
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_admin1_polygon({province_column})
|
||||
```
|
||||
|
||||
### cdb_geocode_admin1_polygon(_admin1_name text, country_name text_)
|
||||
@@ -81,13 +81,13 @@ Geometry (polygon, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_admin1_polygon('Alicante', 'Spain')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_admin1_polygon({province_column}, {country_column})
|
||||
```
|
||||
|
||||
@@ -112,13 +112,13 @@ Geometry (point, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_namedplace_point('Barcelona')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_namedplace_point({city_column})
|
||||
```
|
||||
|
||||
@@ -139,13 +139,13 @@ Geometry (point, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_namedplace_point('Barcelona', 'Spain')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_namedplace_point({city_column}, 'Spain')
|
||||
```
|
||||
|
||||
@@ -167,14 +167,14 @@ Geometry (point, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_namedplace_point('New York', 'New York', 'USA')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_namedplace_point({city_column}, {province_column}, 'Spain')
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_namedplace_point({city_column}, {province_column}, 'USA')
|
||||
```
|
||||
|
||||
## Postal codes geocoder
|
||||
@@ -198,14 +198,14 @@ Geometry (polygon, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_postalcode_polygon('11211', 'USA')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_postalcode_polygon({postal_code_column}, 'Spain')
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_postalcode_polygon({postal_code_column}, 'USA')
|
||||
```
|
||||
|
||||
**Note:** For the USA, US Census ZCTAs are considered.
|
||||
@@ -227,17 +227,17 @@ Geometry (point, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_postalcode_point('11211', 'USA')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_postalcode_point({postal_code_column}, 'United States')
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_postalcode_point({postal_code_column}, 'USA')
|
||||
```
|
||||
|
||||
## IP addresses Geocoder
|
||||
## IP addresses geocoder
|
||||
|
||||
This function provides an IP address geocoding service, for both IPv4 and IPv6 addresses.
|
||||
|
||||
@@ -258,12 +258,55 @@ Geometry (point, EPSG 4326) or null
|
||||
|
||||
##### Select
|
||||
|
||||
```sql
|
||||
```bash
|
||||
SELECT cdb_geocode_ipaddress_point('102.23.34.1')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```sql
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_ipaddress_point('102.23.34.1')
|
||||
```
|
||||
## Street-level geocoder
|
||||
|
||||
This function provides a street-level geocoding service. This service uses the street level geocoder defined for the user (currently, only the Here geocoder is available).
|
||||
|
||||
**This service is subject to quota limitations, and extra fees may apply.** Please view our [terms and conditions](https://cartodb.com/terms/)
|
||||
|
||||
Be mindful of the following when using this function:
|
||||
|
||||
- **One credit per function call will be consumed**, and the results are not cached. If the query applies to a N rows dataset, then N credits will be used.
|
||||
- You are discouraged from using dynamic queries to the Geocoder API in your maps. This can result in credits consumption per map view. Note: **queries to the Geocoder API in your maps may be forbidden in the future**.
|
||||
- You are advised to store results of Geocoder API queries into your datasets and refresh them as needed, so that you can have finer control on your credits' usage.
|
||||
|
||||
### cdb_geocode_street_point(_search_text text, [city text], [state text], [country text]_)
|
||||
|
||||
#### Arguments
|
||||
|
||||
Name | Type | Description
|
||||
--- | --- | ---
|
||||
`searchtext` | `text` | searchtext contains free-form text containing address elements. You can specify the searchtext parameter by itself, or you can specify it with other parameters to narrow your search. For example, you can specify the state or country parameters, along with a free-form address in the searchtext field.
|
||||
`city` | `text` | (Optional) Name of the city
|
||||
`state` | `text` | (Optional) Name of the state
|
||||
`country` | `text` | (Optional) Name of the country
|
||||
|
||||
#### Returns
|
||||
|
||||
Geometry (point, EPSG 4326) or null
|
||||
|
||||
#### Example
|
||||
|
||||
##### Select
|
||||
|
||||
```bash
|
||||
SELECT cdb_geocode_street_point('651 Lombard Street, San Francisco, California, United States')
|
||||
SELECT cdb_geocode_street_point('651 Lombard Street', 'San Francisco')
|
||||
SELECT cdb_geocode_street_point('651 Lombard Street', 'San Francisco', 'California')
|
||||
SELECT cdb_geocode_street_point('651 Lombard Street', 'San Francisco', 'California', 'United States')
|
||||
```
|
||||
|
||||
##### Update
|
||||
|
||||
```bash
|
||||
UPDATE {tablename} SET the_geom = cdb_geocode_street_point({street_name_column})
|
||||
```
|
||||
|
||||
@@ -49,5 +49,4 @@
|
||||
- name: cdb_geocode_ipaddress_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: ip_address, type: text}
|
||||
|
||||
- { name: ip_address, type: text}
|
||||
60
interface_0.1.0.yaml
Normal file
60
interface_0.1.0.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
- name: cdb_geocode_admin0_polygon
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: country_name, type: text }
|
||||
|
||||
- name: cdb_geocode_admin1_polygon
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: admin1_name, type: text }
|
||||
|
||||
- name: cdb_geocode_admin1_polygon
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: admin1_name, type: text }
|
||||
- { name: country_name, type: text }
|
||||
|
||||
- name: cdb_geocode_namedplace_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: city_name, type: text}
|
||||
|
||||
- name: cdb_geocode_namedplace_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: city_name, type: text}
|
||||
- { name: country_name, type: text}
|
||||
|
||||
- name: cdb_geocode_namedplace_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: city_name, type: text}
|
||||
- { name: admin1_name, type: text}
|
||||
- { name: country_name, type: text}
|
||||
|
||||
|
||||
- name: cdb_geocode_postalcode_polygon
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: postal_code, type: text}
|
||||
- { name: country_name, type: text}
|
||||
|
||||
- name: cdb_geocode_postalcode_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: postal_code, type: text}
|
||||
- { name: country_name, type: text}
|
||||
|
||||
- name: cdb_geocode_ipaddress_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: ip_address, type: text}
|
||||
|
||||
- name: cdb_geocode_street_point
|
||||
return_type: Geometry
|
||||
params:
|
||||
- { name: searchtext, type: text}
|
||||
- { name: city, type: text, default: 'NULL'}
|
||||
- { name: state_province, type: text, default: 'NULL'}
|
||||
- { name: country, type: text, default: 'NULL'}
|
||||
3
server/extension/.gitignore
vendored
3
server/extension/.gitignore
vendored
@@ -2,4 +2,5 @@ results/
|
||||
regression.diffs
|
||||
regression.out
|
||||
cdb_geocoder_server--0.0.1.sql
|
||||
|
||||
cdb_geocoder_server--0.1.0.sql
|
||||
cdb_geocoder_server--0.2.0.sql
|
||||
|
||||
@@ -3,24 +3,41 @@
|
||||
EXTENSION = cdb_geocoder_server
|
||||
EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
|
||||
|
||||
DATA = $(EXTENSION)--$(EXTVERSION).sql
|
||||
# The new version to be generated from templates
|
||||
NEW_EXTENSION_ARTIFACT = $(EXTENSION)--$(EXTVERSION).sql
|
||||
|
||||
REGRESS = $(notdir $(basename $(wildcard sql/*test.sql)))
|
||||
# DATA is a special variable used by postgres build infrastructure
|
||||
# These are the files to be installed in the server shared dir,
|
||||
# for installation from scratch, upgrades and downgrades.
|
||||
# @see http://www.postgresql.org/docs/current/static/extend-pgxs.html
|
||||
DATA = $(NEW_EXTENSION_ARTIFACT) \
|
||||
cdb_geocoder_server--0.0.1.sql \
|
||||
cdb_geocoder_server--0.1.0.sql \
|
||||
cdb_geocoder_server--0.1.0--0.0.1.sql \
|
||||
cdb_geocoder_server--0.0.1--0.1.0.sql \
|
||||
cdb_geocoder_server--0.2.0--0.1.0.sql \
|
||||
cdb_geocoder_server--0.1.0--0.2.0.sql
|
||||
|
||||
|
||||
REGRESS = $(notdir $(basename $(wildcard test/$(EXTVERSION)/sql/*test.sql)))
|
||||
TEST_DIR = test/$(EXTVERSION)
|
||||
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)'
|
||||
|
||||
# postgres build stuff
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
|
||||
SOURCES_DATA_DIR = sql/$(EXTVERSION)
|
||||
|
||||
SOURCES_DATA = $(wildcard sql/$(EXTVERSION)/*.sql)
|
||||
|
||||
$(DATA): $(SOURCES_DATA)
|
||||
$(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA)
|
||||
rm -f $@
|
||||
cat $(SOURCES_DATA) >> $@
|
||||
cat $(SOURCES_DATA_DIR)/*.sql >> $@
|
||||
|
||||
all: $(DATA)
|
||||
|
||||
# Only meant for development time, do not use once a version is released
|
||||
devclean:
|
||||
rm -f $(DATA)
|
||||
rm -f $(NEW_EXTENSION_ARTIFACT)
|
||||
|
||||
142
server/extension/cdb_geocoder_server--0.0.1--0.1.0.sql
Normal file
142
server/extension/cdb_geocoder_server--0.0.1--0.1.0.sql
Normal file
@@ -0,0 +1,142 @@
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf_v2(config_key text)
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf_query = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(config_key)
|
||||
conf = plpy.execute(conf_query)[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_geocoder import redis_helper
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = redis_helper.RedisHelper(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = redis_helper.RedisHelper(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_geocoder import config_helper
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = config_helper.GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
-- Geocodes a street address given a searchtext and a state and/or country
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server.cdb_geocode_street_point(TEXT, TEXT, TEXT, TEXT);
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
plpy.execute("SELECT cdb_geocoder_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
if user_geocoder_config.heremaps_geocoder:
|
||||
here_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
elif user_geocoder_config.google_geocoder:
|
||||
google_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
else:
|
||||
plpy.error('Requested geocoder is not available')
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from heremaps import heremapsgeocoder
|
||||
from cartodb_geocoder import quota_service
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = quota_service.QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = heremapsgeocoder.Geocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
results = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
coordinates = geocoder.extract_lng_lat_from_result(results[0])
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
except heremapsgeocoder.EmptyGeocoderResponse:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.error('Google geocoder is not available yet')
|
||||
return None
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- We apply again the grants to include the new functions
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
539
server/extension/cdb_geocoder_server--0.0.1.sql
Normal file
539
server/extension/cdb_geocoder_server--0.0.1.sql
Normal file
@@ -0,0 +1,539 @@
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
CREATE TYPE cdb_geocoder_server._redis_conf_params AS (
|
||||
sentinel_host text,
|
||||
sentinel_port int,
|
||||
sentinel_master_id text,
|
||||
redis_db text,
|
||||
timeout float
|
||||
);
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf()
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('redis_conf') conf")[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
if user_id in GD and 'redis_connection' in GD[user_id]:
|
||||
return False
|
||||
else:
|
||||
from cartodb_geocoder import redis_helper
|
||||
config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf() c;""")[0]
|
||||
redis_connection = redis_helper.RedisHelper(config_params['sentinel_host'],
|
||||
config_params['sentinel_port'],
|
||||
config_params['sentinel_master_id'],
|
||||
timeout=config_params['timeout'],
|
||||
redis_db=config_params['redis_db']).redis_connection()
|
||||
GD[user_id] = {'redis_connection': redis_connection}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu;-- Geocodes a street address given a searchtext and a state and/or country
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point(searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry
|
||||
AS $$
|
||||
import json
|
||||
from heremaps import heremapsgeocoder
|
||||
|
||||
heremaps_conf = json.loads(plpy.execute("SELECT cdb_geocoder_server._get_conf('heremaps')", 1)[0]['get_conf'])
|
||||
|
||||
app_id = heremaps_conf['geocoder']['app_id']
|
||||
app_code = heremaps_conf['geocoder']['app_code']
|
||||
|
||||
geocoder = heremapsgeocoder.Geocoder(app_id, app_code)
|
||||
|
||||
results = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
coordinates = geocoder.extract_lng_lat_from_result(results[0])
|
||||
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
|
||||
return point['st_setsrid']
|
||||
$$ LANGUAGE plpythonu;-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin0_polygons')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin0_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin0_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin0_polygon(country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT n.the_geom as geom INTO ret
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT country_name q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [admin1_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1, $2) AS mypolygon", ["text", "text"])
|
||||
rv = plpy.execute(plan, [admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (
|
||||
SELECT
|
||||
trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q
|
||||
) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r)
|
||||
SELECT
|
||||
geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1) AS mypoint", ["text"])
|
||||
rv = plpy.execute(plan, [city_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2) AS mypoint", ["text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2, $3) AS mypoint", ["text", "text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH inputcountry AS (
|
||||
SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1
|
||||
),
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1) AS point", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1, $2) AS point", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_polygon')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1) AS polygon", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_polygon')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1, $2) AS polygon", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_ipaddress_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_ipaddress_point($1) AS point", ["TEXT"])
|
||||
rv = plpy.execute(plan, [ip], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_ipaddress_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_ipaddress_point(ip text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
|
||||
new_ip INET;
|
||||
BEGIN
|
||||
BEGIN
|
||||
IF family(ip::inet) = 6 THEN
|
||||
new_ip := ip::inet;
|
||||
ELSE
|
||||
new_ip := ('::ffff:' || ip)::inet;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT NULL as geom INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
|
||||
WITH
|
||||
ips AS (SELECT ip s, new_ip net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT geom INTO ret
|
||||
FROM matches;
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_catalog.pg_user
|
||||
WHERE usename = 'geocoder_api') THEN
|
||||
|
||||
CREATE USER geocoder_api;
|
||||
END IF;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
END$$;
|
||||
29
server/extension/cdb_geocoder_server--0.1.0--0.0.1.sql
Normal file
29
server/extension/cdb_geocoder_server--0.1.0--0.0.1.sql
Normal file
@@ -0,0 +1,29 @@
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server._get_redis_conf_v2(text);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server._connect_to_redis(text);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server._get_geocoder_config(text, text);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server.cdb_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server.cdb_geocode_street_point_v2(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server._cdb_here_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||
DROP FUNCTION IF EXISTS cdb_geocoder_server._cdb_google_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point(searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry
|
||||
AS $$
|
||||
import json
|
||||
from heremaps import heremapsgeocoder
|
||||
|
||||
heremaps_conf = json.loads(plpy.execute("SELECT cdb_geocoder_server._get_conf('heremaps')", 1)[0]['get_conf'])
|
||||
|
||||
app_id = heremaps_conf['geocoder']['app_id']
|
||||
app_code = heremaps_conf['geocoder']['app_code']
|
||||
|
||||
geocoder = heremapsgeocoder.Geocoder(app_id, app_code)
|
||||
|
||||
results = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
coordinates = geocoder.extract_lng_lat_from_result(results[0])
|
||||
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
|
||||
return point['st_setsrid']
|
||||
$$ LANGUAGE plpythonu;
|
||||
122
server/extension/cdb_geocoder_server--0.1.0--0.2.0.sql
Normal file
122
server/extension/cdb_geocoder_server--0.1.0--0.2.0.sql
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_services.metrics import GeocoderConfig
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_services.tools import RedisConnection
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = RedisConnection(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = RedisConnection(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.here import HereMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.google import GoogleMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
|
||||
try:
|
||||
geocoder = GoogleMapsGeocoder(user_geocoder_config.google_client_id, user_geocoder_config.google_api_key)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using google maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
615
server/extension/cdb_geocoder_server--0.1.0.sql
Normal file
615
server/extension/cdb_geocoder_server--0.1.0.sql
Normal file
@@ -0,0 +1,615 @@
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
CREATE TYPE cdb_geocoder_server._redis_conf_params AS (
|
||||
sentinel_host text,
|
||||
sentinel_port int,
|
||||
sentinel_master_id text,
|
||||
redis_db text,
|
||||
timeout float
|
||||
);
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf_v2(config_key text)
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf_query = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(config_key)
|
||||
conf = plpy.execute(conf_query)[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_geocoder import redis_helper
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = redis_helper.RedisHelper(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = redis_helper.RedisHelper(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_geocoder import config_helper
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = config_helper.GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
-- Geocodes a street address given a searchtext and a state and/or country
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
plpy.execute("SELECT cdb_geocoder_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
if user_geocoder_config.heremaps_geocoder:
|
||||
here_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
elif user_geocoder_config.google_geocoder:
|
||||
google_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
else:
|
||||
plpy.error('Requested geocoder is not available')
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from heremaps import heremapsgeocoder
|
||||
from cartodb_geocoder import quota_service
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = quota_service.QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = heremapsgeocoder.Geocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
results = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
coordinates = geocoder.extract_lng_lat_from_result(results[0])
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
except heremapsgeocoder.EmptyGeocoderResponse:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.error('Google geocoder is not available yet')
|
||||
return None
|
||||
$$ LANGUAGE plpythonu;
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin0_polygons')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin0_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin0_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin0_polygon(country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT n.the_geom as geom INTO ret
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT country_name q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [admin1_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1, $2) AS mypolygon", ["text", "text"])
|
||||
rv = plpy.execute(plan, [admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (
|
||||
SELECT
|
||||
trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q
|
||||
) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r)
|
||||
SELECT
|
||||
geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1) AS mypoint", ["text"])
|
||||
rv = plpy.execute(plan, [city_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2) AS mypoint", ["text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2, $3) AS mypoint", ["text", "text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH inputcountry AS (
|
||||
SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1
|
||||
),
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1) AS point", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1, $2) AS point", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_polygon')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1) AS polygon", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_polygon')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1, $2) AS polygon", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_ipaddress_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_ipaddress_point($1) AS point", ["TEXT"])
|
||||
rv = plpy.execute(plan, [ip], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_ipaddress_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_ipaddress_point(ip text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
|
||||
new_ip INET;
|
||||
BEGIN
|
||||
BEGIN
|
||||
IF family(ip::inet) = 6 THEN
|
||||
new_ip := ip::inet;
|
||||
ELSE
|
||||
new_ip := ('::ffff:' || ip)::inet;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT NULL as geom INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
|
||||
WITH
|
||||
ips AS (SELECT ip s, new_ip net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT geom INTO ret
|
||||
FROM matches;
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_catalog.pg_user
|
||||
WHERE usename = 'geocoder_api') THEN
|
||||
|
||||
CREATE USER geocoder_api;
|
||||
END IF;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
END$$;
|
||||
95
server/extension/cdb_geocoder_server--0.2.0--0.1.0.sql
Normal file
95
server/extension/cdb_geocoder_server--0.2.0--0.1.0.sql
Normal file
@@ -0,0 +1,95 @@
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_geocoder import config_helper
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = config_helper.GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_geocoder import redis_helper
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = redis_helper.RedisHelper(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = redis_helper.RedisHelper(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from heremaps import heremapsgeocoder
|
||||
from cartodb_geocoder import quota_service
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = quota_service.QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = heremapsgeocoder.Geocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
coordinates = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.error('Google geocoder is not available yet')
|
||||
return None
|
||||
$$ LANGUAGE plpythonu;
|
||||
642
server/extension/cdb_geocoder_server--0.2.0.sql
Normal file
642
server/extension/cdb_geocoder_server--0.2.0.sql
Normal file
@@ -0,0 +1,642 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
CREATE TYPE cdb_geocoder_server._redis_conf_params AS (
|
||||
sentinel_host text,
|
||||
sentinel_port int,
|
||||
sentinel_master_id text,
|
||||
redis_db text,
|
||||
timeout float
|
||||
);
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf_v2(config_key text)
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf_query = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(config_key)
|
||||
conf = plpy.execute(conf_query)[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_services.tools import RedisConnection
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = RedisConnection(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = RedisConnection(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_services.metrics import GeocoderConfig
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
-- Geocodes a street address given a searchtext and a state and/or country
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point_v2(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
plpy.execute("SELECT cdb_geocoder_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
if user_geocoder_config.heremaps_geocoder:
|
||||
here_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
elif user_geocoder_config.google_geocoder:
|
||||
google_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
else:
|
||||
plpy.error('Requested geocoder is not available')
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.here import HereMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.google import GoogleMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
|
||||
try:
|
||||
geocoder = GoogleMapsGeocoder(user_geocoder_config.google_client_id, user_geocoder_config.google_api_key)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using google maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin0_polygons')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin0_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin0_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin0_polygon(country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT n.the_geom as geom INTO ret
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT country_name q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [admin1_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1, $2) AS mypolygon", ["text", "text"])
|
||||
rv = plpy.execute(plan, [admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (
|
||||
SELECT
|
||||
trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q
|
||||
) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r)
|
||||
SELECT
|
||||
geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1) AS mypoint", ["text"])
|
||||
rv = plpy.execute(plan, [city_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2) AS mypoint", ["text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2, $3) AS mypoint", ["text", "text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH inputcountry AS (
|
||||
SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1
|
||||
),
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1) AS point", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1, $2) AS point", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_polygon')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1) AS polygon", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_polygon')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1, $2) AS polygon", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_ipaddress_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_ipaddress_point($1) AS point", ["TEXT"])
|
||||
rv = plpy.execute(plan, [ip], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_ipaddress_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_ipaddress_point(ip text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
|
||||
new_ip INET;
|
||||
BEGIN
|
||||
BEGIN
|
||||
IF family(ip::inet) = 6 THEN
|
||||
new_ip := ip::inet;
|
||||
ELSE
|
||||
new_ip := ('::ffff:' || ip)::inet;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT NULL as geom INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
|
||||
WITH
|
||||
ips AS (SELECT ip s, new_ip net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT geom INTO ret
|
||||
FROM matches;
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_catalog.pg_user
|
||||
WHERE usename = 'geocoder_api') THEN
|
||||
|
||||
CREATE USER geocoder_api;
|
||||
END IF;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
END$$;
|
||||
@@ -1,6 +1,6 @@
|
||||
# cdb geocoder server extension
|
||||
comment = 'CartoDB server geocoder extension'
|
||||
default_version = '0.0.1'
|
||||
default_version = '0.2.0'
|
||||
requires = 'plpythonu, postgis, cdb_geocoder'
|
||||
superuser = true
|
||||
schema = cdb_geocoder_server
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
|
||||
@@ -41,4 +41,4 @@ RETURNS boolean AS $$
|
||||
redis_db=config_params['redis_db']).redis_connection()
|
||||
GD[user_id] = {'redis_connection': redis_connection}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu;
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
3
server/extension/sql/0.1.0/00_header.sql
Normal file
3
server/extension/sql/0.1.0/00_header.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
57
server/extension/sql/0.1.0/10_redis_helper.sql
Normal file
57
server/extension/sql/0.1.0/10_redis_helper.sql
Normal file
@@ -0,0 +1,57 @@
|
||||
CREATE TYPE cdb_geocoder_server._redis_conf_params AS (
|
||||
sentinel_host text,
|
||||
sentinel_port int,
|
||||
sentinel_master_id text,
|
||||
redis_db text,
|
||||
timeout float
|
||||
);
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf_v2(config_key text)
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf_query = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(config_key)
|
||||
conf = plpy.execute(conf_query)[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_geocoder import redis_helper
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = redis_helper.RedisHelper(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = redis_helper.RedisHelper(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
25
server/extension/sql/0.1.0/15_config_helper.sql
Normal file
25
server/extension/sql/0.1.0/15_config_helper.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_geocoder import config_helper
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = config_helper.GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
58
server/extension/sql/0.1.0/20_geocode_street.sql
Normal file
58
server/extension/sql/0.1.0/20_geocode_street.sql
Normal file
@@ -0,0 +1,58 @@
|
||||
-- Geocodes a street address given a searchtext and a state and/or country
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
plpy.execute("SELECT cdb_geocoder_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
if user_geocoder_config.heremaps_geocoder:
|
||||
here_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
elif user_geocoder_config.google_geocoder:
|
||||
google_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
else:
|
||||
plpy.error('Requested geocoder is not available')
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from heremaps import heremapsgeocoder
|
||||
from cartodb_geocoder import quota_service
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = quota_service.QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = heremapsgeocoder.Geocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
results = geocoder.geocode_address(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
coordinates = geocoder.extract_lng_lat_from_result(results[0])
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
except heremapsgeocoder.EmptyGeocoderResponse:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.error('Google geocoder is not available yet')
|
||||
return None
|
||||
$$ LANGUAGE plpythonu;
|
||||
37
server/extension/sql/0.1.0/30_admin0.sql
Normal file
37
server/extension/sql/0.1.0/30_admin0.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin0_polygons')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin0_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin0_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin0_polygon(country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT n.the_geom as geom INTO ret
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT country_name q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
89
server/extension/sql/0.1.0/40_admin1.sql
Normal file
89
server/extension/sql/0.1.0/40_admin1.sql
Normal file
@@ -0,0 +1,89 @@
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [admin1_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1, $2) AS mypolygon", ["text", "text"])
|
||||
rv = plpy.execute(plan, [admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (
|
||||
SELECT
|
||||
trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q
|
||||
) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r)
|
||||
SELECT
|
||||
geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
121
server/extension/sql/0.1.0/50_namedplaces.sql
Normal file
121
server/extension/sql/0.1.0/50_namedplaces.sql
Normal file
@@ -0,0 +1,121 @@
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1) AS mypoint", ["text"])
|
||||
rv = plpy.execute(plan, [city_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2) AS mypoint", ["text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2, $3) AS mypoint", ["text", "text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH inputcountry AS (
|
||||
SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1
|
||||
),
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
162
server/extension/sql/0.1.0/60_postalcodes.sql
Normal file
162
server/extension/sql/0.1.0/60_postalcodes.sql
Normal file
@@ -0,0 +1,162 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1) AS point", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1, $2) AS point", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_polygon')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1) AS polygon", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_polygon')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1, $2) AS polygon", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
49
server/extension/sql/0.1.0/70_ips.sql
Normal file
49
server/extension/sql/0.1.0/70_ips.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_ipaddress_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_ipaddress_point($1) AS point", ["TEXT"])
|
||||
rv = plpy.execute(plan, [ip], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_ipaddress_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_ipaddress_point(ip text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
|
||||
new_ip INET;
|
||||
BEGIN
|
||||
BEGIN
|
||||
IF family(ip::inet) = 6 THEN
|
||||
new_ip := ip::inet;
|
||||
ELSE
|
||||
new_ip := ('::ffff:' || ip)::inet;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT NULL as geom INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
|
||||
WITH
|
||||
ips AS (SELECT ip s, new_ip net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT geom INTO ret
|
||||
FROM matches;
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
15
server/extension/sql/0.1.0/90_geocoder_server_user.sql
Normal file
15
server/extension/sql/0.1.0/90_geocoder_server_user.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_catalog.pg_user
|
||||
WHERE usename = 'geocoder_api') THEN
|
||||
|
||||
CREATE USER geocoder_api;
|
||||
END IF;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
END$$;
|
||||
3
server/extension/sql/0.2.0/00_header.sql
Normal file
3
server/extension/sql/0.2.0/00_header.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_server" to load this file. \quit
|
||||
57
server/extension/sql/0.2.0/10_redis_helper.sql
Normal file
57
server/extension/sql/0.2.0/10_redis_helper.sql
Normal file
@@ -0,0 +1,57 @@
|
||||
CREATE TYPE cdb_geocoder_server._redis_conf_params AS (
|
||||
sentinel_host text,
|
||||
sentinel_port int,
|
||||
sentinel_master_id text,
|
||||
redis_db text,
|
||||
timeout float
|
||||
);
|
||||
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_redis_conf_v2(config_key text)
|
||||
RETURNS cdb_geocoder_server._redis_conf_params AS $$
|
||||
conf_query = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(config_key)
|
||||
conf = plpy.execute(conf_query)[0]['conf']
|
||||
if conf is None:
|
||||
plpy.error("There is no redis configuration defined")
|
||||
else:
|
||||
import json
|
||||
params = json.loads(conf)
|
||||
return {
|
||||
"sentinel_host": params['sentinel_host'],
|
||||
"sentinel_port": params['sentinel_port'],
|
||||
"sentinel_master_id": params['sentinel_master_id'],
|
||||
"timeout": params['timeout'],
|
||||
"redis_db": params['redis_db']
|
||||
}
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- Get the connection to redis from cache or create a new one
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._connect_to_redis(user_id text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "redis_connection_{0}".format(user_id)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
from cartodb_services.tools import RedisConnection
|
||||
metadata_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metadata_config') c;""")[0]
|
||||
metrics_config_params = plpy.execute("""select c.sentinel_host, c.sentinel_port,
|
||||
c.sentinel_master_id, c.timeout, c.redis_db
|
||||
from cdb_geocoder_server._get_redis_conf_v2('redis_metrics_config') c;""")[0]
|
||||
redis_metadata_connection = RedisConnection(metadata_config_params['sentinel_host'],
|
||||
metadata_config_params['sentinel_port'],
|
||||
metadata_config_params['sentinel_master_id'],
|
||||
timeout=metadata_config_params['timeout'],
|
||||
redis_db=metadata_config_params['redis_db']).redis_connection()
|
||||
redis_metrics_connection = RedisConnection(metrics_config_params['sentinel_host'],
|
||||
metrics_config_params['sentinel_port'],
|
||||
metrics_config_params['sentinel_master_id'],
|
||||
timeout=metrics_config_params['timeout'],
|
||||
redis_db=metrics_config_params['redis_db']).redis_connection()
|
||||
GD[cache_key] = {
|
||||
'redis_metadata_connection': redis_metadata_connection,
|
||||
'redis_metrics_connection': redis_metrics_connection,
|
||||
}
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
25
server/extension/sql/0.2.0/15_config_helper.sql
Normal file
25
server/extension/sql/0.2.0/15_config_helper.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
-- Get the Redis configuration from the _conf table --
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._get_geocoder_config(username text, orgname text)
|
||||
RETURNS boolean AS $$
|
||||
cache_key = "user_geocoder_config_{0}".format(username)
|
||||
if cache_key in GD:
|
||||
return False
|
||||
else:
|
||||
import json
|
||||
from cartodb_services.metrics import GeocoderConfig
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection']
|
||||
heremaps_conf_json = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('heremaps_conf') as heremaps_conf", 1)[0]['heremaps_conf']
|
||||
if not heremaps_conf_json:
|
||||
heremaps_app_id = None
|
||||
heremaps_app_code = None
|
||||
else:
|
||||
heremaps_conf = json.loads(heremaps_conf_json)
|
||||
heremaps_app_id = heremaps_conf['app_id']
|
||||
heremaps_app_code = heremaps_conf['app_code']
|
||||
geocoder_config = GeocoderConfig(redis_conn, username, orgname, heremaps_app_id, heremaps_app_code)
|
||||
# --Think about the security concerns with this kind of global cache, it should be only available
|
||||
# --for this user session but...
|
||||
GD[cache_key] = geocoder_config
|
||||
return True
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
84
server/extension/sql/0.2.0/20_geocode_street.sql
Normal file
84
server/extension/sql/0.2.0/20_geocode_street.sql
Normal file
@@ -0,0 +1,84 @@
|
||||
-- Geocodes a street address given a searchtext and a state and/or country
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_street_point_v2(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.execute("SELECT cdb_geocoder_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
plpy.execute("SELECT cdb_geocoder_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
if user_geocoder_config.heremaps_geocoder:
|
||||
here_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
elif user_geocoder_config.google_geocoder:
|
||||
google_plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||
else:
|
||||
plpy.error('Requested geocoder is not available')
|
||||
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.here import HereMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
plpy.error('You have reach the limit of your quota')
|
||||
|
||||
try:
|
||||
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||
RETURNS Geometry AS $$
|
||||
from cartodb_services.google import GoogleMapsGeocoder
|
||||
from cartodb_services.metrics import QuotaService
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||
quota_service = QuotaService(user_geocoder_config, redis_conn)
|
||||
|
||||
try:
|
||||
geocoder = GoogleMapsGeocoder(user_geocoder_config.google_client_id, user_geocoder_config.google_api_key)
|
||||
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
|
||||
if coordinates:
|
||||
quota_service.increment_success_geocoder_use()
|
||||
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||
return point['st_setsrid']
|
||||
else:
|
||||
quota_service.increment_empty_geocoder_use()
|
||||
return None
|
||||
except BaseException as e:
|
||||
import sys, traceback
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
quota_service.increment_failed_geocoder_use()
|
||||
error_msg = 'There was an error trying to geocode using google maps geocoder: {0}'.format(e)
|
||||
plpy.notice(traceback.format_tb(traceback_))
|
||||
plpy.error(error_msg)
|
||||
finally:
|
||||
quota_service.increment_total_geocoder_use()
|
||||
$$ LANGUAGE plpythonu;
|
||||
37
server/extension/sql/0.2.0/30_admin0.sql
Normal file
37
server/extension/sql/0.2.0/30_admin0.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin0_polygons')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin0_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin0_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin0_polygon(country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT n.the_geom as geom INTO ret
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT country_name q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
89
server/extension/sql/0.2.0/40_admin1.sql
Normal file
89
server/extension/sql/0.2.0/40_admin1.sql
Normal file
@@ -0,0 +1,89 @@
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1) AS mypolygon", ["text"])
|
||||
rv = plpy.execute(plan, [admin1_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygons')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_admin1_polygon($1, $2) AS mypolygon", ["text", "text"])
|
||||
rv = plpy.execute(plan, [admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from cdb_geocode_admin1_polygon(admin1_name text, country_name text)')
|
||||
return rv[0]["mypolygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (
|
||||
SELECT
|
||||
trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q
|
||||
) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r)
|
||||
SELECT
|
||||
geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
121
server/extension/sql/0.2.0/50_namedplaces.sql
Normal file
121
server/extension/sql/0.2.0/50_namedplaces.sql
Normal file
@@ -0,0 +1,121 @@
|
||||
-- Interfacess of the server extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1) AS mypoint", ["text"])
|
||||
rv = plpy.execute(plan, [city_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2) AS mypoint", ["text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_namedplace_point($1, $2, $3) AS mypoint", ["text", "text", "text"])
|
||||
rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1)
|
||||
|
||||
plpy.debug('Returning from Returning from geocode_namedplace')
|
||||
return rv[0]["mypoint"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
WITH inputcountry AS (
|
||||
SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1
|
||||
),
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT geom FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM next
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
162
server/extension/sql/0.2.0/60_postalcodes.sql
Normal file
162
server/extension/sql/0.2.0/60_postalcodes.sql
Normal file
@@ -0,0 +1,162 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1) AS point", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_point($1, $2) AS point", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_polygon')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1) AS polygon", ["text"])
|
||||
rv = plpy.execute(plan, [code], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_polygon')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_postalcode_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_postalcode_polygon($1, $2) AS polygon", ["TEXT", "TEXT"])
|
||||
rv = plpy.execute(plan, [code, country], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_postalcode_point')
|
||||
return rv[0]["polygon"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_point(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_postalcode_polygon(code text, country text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
BEGIN
|
||||
SELECT geom INTO ret
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(country) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT code q) d
|
||||
) v;
|
||||
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
49
server/extension/sql/0.2.0/70_ips.sql
Normal file
49
server/extension/sql/0.2.0/70_ips.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- Interface of the server extension
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text)
|
||||
RETURNS Geometry AS $$
|
||||
plpy.debug('Entering _cdb_geocode_ipaddress_point')
|
||||
plpy.debug('user = %s' % username)
|
||||
|
||||
#--TODO: rate limiting check
|
||||
#--TODO: quota check
|
||||
|
||||
#-- Copied from the doc, see http://www.postgresql.org/docs/9.4/static/plpython-database.html
|
||||
plan = plpy.prepare("SELECT cdb_geocoder_server._cdb_geocode_ipaddress_point($1) AS point", ["TEXT"])
|
||||
rv = plpy.execute(plan, [ip], 1)
|
||||
|
||||
plpy.debug('Returning from _cdb_geocode_ipaddress_point')
|
||||
return rv[0]["point"]
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Implementation of the server extension
|
||||
-- Note: these functions depend on the cdb_geocoder extension
|
||||
CREATE OR REPLACE FUNCTION cdb_geocoder_server._cdb_geocode_ipaddress_point(ip text)
|
||||
RETURNS Geometry AS $$
|
||||
DECLARE
|
||||
ret Geometry;
|
||||
|
||||
new_ip INET;
|
||||
BEGIN
|
||||
BEGIN
|
||||
IF family(ip::inet) = 6 THEN
|
||||
new_ip := ip::inet;
|
||||
ELSE
|
||||
new_ip := ('::ffff:' || ip)::inet;
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT NULL as geom INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
|
||||
WITH
|
||||
ips AS (SELECT ip s, new_ip net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT geom INTO ret
|
||||
FROM matches;
|
||||
RETURN ret;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
15
server/extension/sql/0.2.0/90_geocoder_server_user.sql
Normal file
15
server/extension/sql/0.2.0/90_geocoder_server_user.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT *
|
||||
FROM pg_catalog.pg_user
|
||||
WHERE usename = 'geocoder_api') THEN
|
||||
|
||||
CREATE USER geocoder_api;
|
||||
END IF;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA cdb_geocoder_server TO geocoder_api;
|
||||
GRANT USAGE ON SCHEMA public TO geocoder_api;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api;
|
||||
END$$;
|
||||
30
server/extension/test/0.1.0/expected/00_install_test.out
Normal file
30
server/extension/test/0.1.0/expected/00_install_test.out
Normal file
@@ -0,0 +1,30 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION cdb_geocoder;
|
||||
-- Install the extension
|
||||
CREATE EXTENSION cdb_geocoder_server;
|
||||
-- Mock the redis server connection to point to this very test db
|
||||
SELECT cartodb.cdb_conf_setconf('redis_conf', '{"sentinel_host": "localhost", "sentinel_port": 26739, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}');
|
||||
cdb_conf_setconf
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Mock the varnish invalidation function
|
||||
-- (used by cdb_geocoder tests)
|
||||
CREATE OR REPLACE FUNCTION public.cdb_invalidate_varnish(table_name text) RETURNS void AS $$
|
||||
BEGIN
|
||||
RETURN;
|
||||
END
|
||||
$$
|
||||
LANGUAGE plpgsql;
|
||||
-- Set user quota
|
||||
SELECT cartodb.CDB_SetUserQuotaInBytes(0);
|
||||
cdb_setuserquotainbytes
|
||||
-------------------------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
12
server/extension/test/0.1.0/expected/20_street_test.out
Normal file
12
server/extension/test/0.1.0/expected/20_street_test.out
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Check for namedplaces signatures
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_street_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text, text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
47
server/extension/test/0.1.0/expected/30_admin0_test.out
Normal file
47
server/extension/test/0.1.0/expected/30_admin0_test.out
Normal file
@@ -0,0 +1,47 @@
|
||||
-- Check that the public function is callable, even with no data
|
||||
-- It should return NULL
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin0_polygon('test_user', 'test_orgname', 'Spain');
|
||||
cdb_geocode_admin0_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Insert some dummy synonym
|
||||
INSERT INTO admin0_synonyms (name, adm0_a3) VALUES ('Spain', 'ESP');
|
||||
-- Insert some dummy geometry to return
|
||||
INSERT INTO ne_admin0_v3 (adm0_a3, the_geom) VALUES('ESP', ST_GeomFromText(
|
||||
'POLYGON((-71.1031880899493 42.3152774590236,
|
||||
-71.1031627617667 42.3152960829043,
|
||||
-71.102923838298 42.3149156848307,
|
||||
-71.1031880899493 42.3152774590236))',4326)
|
||||
);
|
||||
-- This should return the polygon inserted above
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin0_polygon('test_user', 'test_orgname', 'Spain');
|
||||
cdb_geocode_admin0_polygon
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
0103000020E61000000100000004000000D0EA37A29AC651C00FD603035B284540FEFCFB379AC651C0C0503E9F5B284540FFDDDD4D96C651C033AC3B284F284540D0EA37A29AC651C00FD603035B284540
|
||||
(1 row)
|
||||
|
||||
-- Check for admin0 signatures
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_admin0_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_admin0_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
81
server/extension/test/0.1.0/expected/40_admin1_test.out
Normal file
81
server/extension/test/0.1.0/expected/40_admin1_test.out
Normal file
@@ -0,0 +1,81 @@
|
||||
-- Check that the public function is callable, even with no data
|
||||
-- It should return NULL
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon('test_user', 'test_orgname', 'California');
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon('test_user', 'test_orgname', 'California', 'United States');
|
||||
cdb_geocode_admin1_polygon
|
||||
----------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Insert dummy data into country decoder table
|
||||
INSERT INTO country_decoder (synonyms, iso3) VALUES (Array['united states'], 'USA');
|
||||
-- Insert some dummy data and geometry to return
|
||||
INSERT INTO global_province_polygons (synonyms, iso3, the_geom) VALUES (Array['california'], 'USA', ST_GeomFromText(
|
||||
'POLYGON((-71.1031880899493 42.3152774590236,
|
||||
-71.1031627617667 42.3152960829043,
|
||||
-71.102923838298 42.3149156848307,
|
||||
-71.1031880899493 42.3152774590236))',4326)
|
||||
);
|
||||
-- This should return the polygon inserted above
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon('test_user', 'test_orgname', 'California');
|
||||
cdb_geocode_admin1_polygon
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
0103000020E61000000100000004000000D0EA37A29AC651C00FD603035B284540FEFCFB379AC651C0C0503E9F5B284540FFDDDD4D96C651C033AC3B284F284540D0EA37A29AC651C00FD603035B284540
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_admin1_polygon('test_user', 'test_orgname', 'California', 'United States');
|
||||
cdb_geocode_admin1_polygon
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
0103000020E61000000100000004000000D0EA37A29AC651C00FD603035B284540FEFCFB379AC651C0C0503E9F5B284540FFDDDD4D96C651C033AC3B284F284540D0EA37A29AC651C00FD603035B284540
|
||||
(1 row)
|
||||
|
||||
-- Check for admin1 signatures
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_admin1_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_admin1_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_admin1_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_admin1_polygon'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
136
server/extension/test/0.1.0/expected/50_namedplaces_test.out
Normal file
136
server/extension/test/0.1.0/expected/50_namedplaces_test.out
Normal file
@@ -0,0 +1,136 @@
|
||||
-- Check that the public function is callable, even with no data
|
||||
-- It should return NULL
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx');
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx', 'Valencia', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Insert dummy data into points table
|
||||
INSERT INTO global_cities_points_limited (geoname_id, name, iso2, admin1, admin2, population, lowername, the_geom) VALUES (3128760, 'Elche', 'ES', 'Valencia', 'AL', 34534, 'elche', ST_GeomFromText(
|
||||
'POINT(0.6983 39.26787)',4326)
|
||||
);
|
||||
-- Insert dummy data into alternates table
|
||||
INSERT INTO global_cities_alternates_limited (geoname_id, name, preferred, lowername, admin1_geonameid, iso2, admin1, the_geom) VALUES (3128760, 'Elx', true, 'elx', '000000', 'ES', 'Valencia', ST_GeomFromText(
|
||||
'POINT(0.6983 39.26787)',4326)
|
||||
);
|
||||
-- Insert dummy data into country decoder table
|
||||
INSERT INTO country_decoder (synonyms, iso2) VALUES (Array['spain'], 'ES');
|
||||
-- Insert dummy data into admin1 decoder table
|
||||
INSERT INTO admin1_decoder (admin1, synonyms, iso2) VALUES ('Valencia', Array['valencia', 'Valencia'], 'ES');
|
||||
-- This should return the point inserted above
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elche');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elche', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elx', 'Valencia', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
SELECT cdb_geocoder_server.cdb_geocode_namedplace_point('test_user', 'test_orgname', 'Elche', 'valencia', 'Spain');
|
||||
cdb_geocode_namedplace_point
|
||||
----------------------------------------------------
|
||||
0101000020E6100000637FD93D7958E63F2ECA6C9049A24340
|
||||
(1 row)
|
||||
|
||||
-- Check for namedplaces signatures
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = 'cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT exists(SELECT *
|
||||
FROM pg_proc p
|
||||
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
|
||||
WHERE ns.nspname = 'cdb_geocoder_server'
|
||||
AND proname = '_cdb_geocode_namedplace_point'
|
||||
AND oidvectortypes(p.proargtypes) = 'text, text, text');
|
||||
exists
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user