Merge pull request #40 from CartoDB/interface-generator

Interface generator
This commit is contained in:
Rafa de la Torre 2015-11-19 15:36:17 +01:00
commit 37116891d3
17 changed files with 157 additions and 232 deletions

View File

@ -12,15 +12,27 @@ PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
SOURCES_DATA_DIR = sql/$(EXTVERSION)
SOURCES_DATA = $(wildcard sql/$(EXTVERSION)/*.sql)
# The interface definition is used along with some templates to automatically generate code
RENDERER = ../sql-template-renderer
INTERFACE_FILE = ../interface.yaml
TEMPLATE_DIR = templates
TEMPLATE_FILES = $(wildcard $(TEMPLATE_DIR)/*.erb)
GENERATED_SQL_FILES = $(patsubst $(TEMPLATE_DIR)/%.erb, $(SOURCES_DATA_DIR)/%.sql, $(TEMPLATE_FILES))
$(GENERATED_SQL_FILES): $(SOURCES_DATA_DIR)/%.sql: $(TEMPLATE_DIR)/%.erb $(INTERFACE_FILE) $(RENDERER)
$(RENDERER) $(INTERFACE_FILE) $< > $@
SOURCES_DATA = $(wildcard $(SOURCES_DATA_DIR)/*.sql) $(GENERATED_SQL_FILES)
$(DATA): $(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 $(GENERATED_SQL_FILES)

View File

@ -24,7 +24,7 @@ PL/pgSQL function cdb_geocoder_client.geocode_postalcode_polygon(text,text) line
(1 row)
SELECT cdb_geocoder_client.geocode_postalcode_point('03204', 'Spain');
NOTICE: cdb_geocoder_client._geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.geocode_postalcode_polygon invoked with params (postgres, some_transaction_id, 03204, Spain)
NOTICE: cdb_geocoder_client._geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.geocode_postalcode_point invoked with params (postgres, some_transaction_id, 03204, Spain)
CONTEXT: SQL statement "SELECT cdb_geocoder_client._geocode_postalcode_point(session_user, txid_current(), postal_code, country_name)"
PL/pgSQL function cdb_geocoder_client.geocode_postalcode_point(text,text) line 5 at SQL statement
geocode_postalcode_point

View File

@ -66,7 +66,7 @@ PL/pgSQL function cdb_geocoder_client.geocode_postalcode_polygon(text,text) line
(1 row)
SELECT cdb_geocoder_client.geocode_postalcode_point('03204', 'Spain');
NOTICE: cdb_geocoder_client._geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.geocode_postalcode_polygon invoked with params (postgres, some_transaction_id, 03204, Spain)
NOTICE: cdb_geocoder_client._geocode_postalcode_point(4): [contrib_regression] REMOTE NOTICE: cdb_geocoder_server.geocode_postalcode_point invoked with params (postgres, some_transaction_id, 03204, Spain)
CONTEXT: SQL statement "SELECT cdb_geocoder_client._geocode_postalcode_point(session_user, txid_current(), postal_code, country_name)"
PL/pgSQL function cdb_geocoder_client.geocode_postalcode_point(text,text) line 5 at SQL statement
geocode_postalcode_point

3
client/sql/0.0.1/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
20_public_functions.sql
30_plproxy_functions.sql
90_grant_execute.sql

View File

@ -1,26 +0,0 @@
--
-- 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.geocode_admin0_polygon(country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_admin0_polygon(session_user, txid_current(), country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
-- TODO: review all permissions stuff [I'd explicitly grant permissions to the public functions]
--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_admin0_polygon(user_id name, tx_id bigint, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_admin0_polygon(user_id, tx_id, country_name);
$$ LANGUAGE plproxy;

View File

@ -1,45 +0,0 @@
--
-- Public geocoder API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
---- geocode_admin1_polygon(admin1_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_admin1_polygon(admin1_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_admin1_polygon(session_user, txid_current(), admin1_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
---- geocode_admin1_polygon(admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_admin1_polygon(admin1_name text, country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_admin1_polygon(session_user, txid_current(), admin1_name, country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
-- TODO: review all permissions stuff [I'd explicitly grant permissions to the public functions]
--------------------------------------------------------------------------------
---- geocode_admin1_polygon(admin1_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_admin1_polygon(user_id name, tx_id bigint, admin1_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_admin1_polygon(user_id, tx_id, admin1_name);
$$ LANGUAGE plproxy;
---- geocode_admin1_polygon(admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_admin1_polygon(user_id name, tx_id bigint, admin1_name text, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_admin1_polygon(user_id, tx_id, admin1_name, country_name);
$$ LANGUAGE plproxy;

View File

@ -1,62 +0,0 @@
--
-- Public geocoder API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
---- geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_namedplace_point(session_user, txid_current(), city_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
---- geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text, country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_namedplace_point(session_user, txid_current(), city_name, country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
---- geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_namedplace_point(session_user, txid_current(), city_name, admin1_name, country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
-- TODO: review all permissions stuff [I'd explicitly grant permissions to the public functions]
--------------------------------------------------------------------------------
---- geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_namedplace_point(user_id name, tx_id bigint, city_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_namedplace_point(user_id, tx_id, city_name);
$$ LANGUAGE plproxy;
---- geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_namedplace_point(user_id name, tx_id bigint, city_name text, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_namedplace_point(user_id, tx_id, city_name, country_name);
$$ LANGUAGE plproxy;
---- geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_namedplace_point(user_id name, tx_id bigint, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_namedplace_point(user_id, tx_id, city_name, admin1_name, country_name);
$$ LANGUAGE plproxy;

View File

@ -1,45 +0,0 @@
--
-- Public geocoder API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
---- geocode_postalcode_polygon(postal_code text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_postalcode_polygon(postal_code text, country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_postalcode_polygon(session_user, txid_current(), postal_code, country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
---- geocode_postalcode_polygon(postal_code integer, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_postalcode_point(postal_code text, country_name text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_postalcode_point(session_user, txid_current(), postal_code, country_name) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
-- TODO: review all permissions stuff [I'd explicitly grant permissions to the public functions]
--------------------------------------------------------------------------------
---- geocode_postalcode_polygon(postal_code text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_postalcode_polygon(user_id name, tx_id bigint, postal_code text, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_postalcode_polygon(user_id, tx_id, postal_code, country_name);
$$ LANGUAGE plproxy;
---- geocode_postalcode_polygon(postal_code text, country_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_postalcode_point(user_id name, tx_id bigint, postal_code text, country_name text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_postalcode_polygon(user_id, tx_id, postal_code, country_name);
$$ LANGUAGE plproxy;

View File

@ -1,27 +0,0 @@
--
-- Public geocoder API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
---- geocode_ipaddress_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client.geocode_ipaddress_point(ip_address text)
RETURNS Geometry AS $$
DECLARE
ret Geometry;
BEGIN
SELECT cdb_geocoder_client._geocode_ipaddress_point(session_user, txid_current(), ip_address) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
-- TODO: review all permissions stuff [I'd explicitly grant permissions to the public functions]
--------------------------------------------------------------------------------
---- geocode_ipaddress_point(ip_address text)
CREATE OR REPLACE FUNCTION cdb_geocoder_client._geocode_ipaddress_point(user_id name, tx_id bigint, ip_address text)
RETURNS Geometry AS $$
CONNECT cdb_geocoder_client._server_conn_str();
SELECT cdb_geocoder_server.geocode_ipaddress_point(user_id, tx_id, ip_address);
$$ LANGUAGE plproxy;

View 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;

View File

@ -1,23 +0,0 @@
-- 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;
--------------------------------------------------------------------------------
-- Explicitly grant permissions to public functions
-- NOTE: All public functions must be listed below, grating permissions to publicuser
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_admin0_polygon(country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_admin1_polygon(admin1_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_admin1_polygon(admin1_name text, country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text, country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_namedplace_point(city_name text, admin1_name text, country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_postalcode_polygon(postal_code text, country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_postalcode_point(postal_code text, country_name text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_geocoder_client.geocode_ipaddress_point(ip_address text) TO publicuser;

View File

@ -0,0 +1,16 @@
--
-- 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 <%= GEOCODER_CLIENT_SCHEMA %>.<%= name %> (<%= params_with_type %>)
RETURNS <%= return_type %> AS $$
DECLARE
ret <%= return_type %>;
BEGIN
SELECT <%= GEOCODER_CLIENT_SCHEMA %>._<%= name %>(session_user, txid_current(), <%= params %>) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;

View File

@ -0,0 +1,5 @@
CREATE OR REPLACE FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>._<%= name %> (user_id name, tx_id bigint, <%= params_with_type %>)
RETURNS Geometry AS $$
CONNECT <%= GEOCODER_CLIENT_SCHEMA %>._server_conn_str();
SELECT cdb_geocoder_server.<%= name %> (user_id, tx_id, <%= params %>);
$$ LANGUAGE plproxy;

View File

@ -0,0 +1 @@
GRANT EXECUTE ON FUNCTION <%= GEOCODER_CLIENT_SCHEMA %>.<%= name %>(<%= params_with_type %>) TO publicuser;

53
interface.yaml Normal file
View File

@ -0,0 +1,53 @@
---
- name: geocode_admin0_polygon
return_type: Geometry
params:
- { name: country_name, type: text }
- name: geocode_admin1_polygon
return_type: Geometry
params:
- { name: admin1_name, type: text }
- name: geocode_admin1_polygon
return_type: Geometry
params:
- { name: admin1_name, type: text }
- { name: country_name, type: text }
- name: geocode_namedplace_point
return_type: Geometry
params:
- { name: city_name, type: text}
- name: geocode_namedplace_point
return_type: Geometry
params:
- { name: city_name, type: text}
- { name: country_name, type: text}
- name: geocode_namedplace_point
return_type: Geometry
params:
- { name: city_name, type: text}
- { name: admin1_name, type: text}
- { name: country_name, type: text}
- name: geocode_postalcode_polygon
return_type: Geometry
params:
- { name: postal_code, type: text}
- { name: country_name, type: text}
- name: geocode_postalcode_point
return_type: Geometry
params:
- { name: postal_code, type: text}
- { name: country_name, type: text}
- name: geocode_ipaddress_point
return_type: Geometry
params:
- { name: ip_address, type: text}

54
sql-template-renderer Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env ruby
# A script to automatically generate SQL files from an interface definition.
# To be called like this: sql-template-renderer interface.csv templates/sql-template.erb
require 'yaml'
require 'erb'
class SqlTemplateRenderer
GEOCODER_CLIENT_SCHEMA = 'cdb_geocoder_client'
def initialize(template_file, function_signature)
@f = function_signature
@template = File.read(template_file)
end
def render
ERB.new(@template).result(binding)
end
def name
@f['name']
end
def return_type
@f['return_type']
end
def params
@f['params'].map { |p| p['name'] }.join(', ')
end
def params_with_type
@f['params'].map { |p| "#{p['name']} #{p['type']}"}.join(', ')
end
end
if ARGV.length != 2 then
puts "Usage: sql-template-renderer <interface.yaml> <template.erb>"
exit
end
interface_source_file = ARGV[0]
template_file = ARGV[1]
functions = YAML.load(File.open(interface_source_file))
functions.each do |f|
puts SqlTemplateRenderer.new(template_file, f).render
end