diff --git a/README.md b/README.md index 4f32055..71777f6 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,9 @@ cartodb-postgresql ================== PostgreSQL extension for CartoDB + +Depdenencies +------------ + + * PostgreSQL 9.3+ + * [Schema triggers extension](https://bitbucket.org/malloclabs/pg_schema_triggers) diff --git a/cartodb_hooks.sql b/cartodb_hooks.sql new file mode 100644 index 0000000..5b46cc7 --- /dev/null +++ b/cartodb_hooks.sql @@ -0,0 +1,160 @@ +LOAD 'schema_triggers.so'; +CREATE EXTENSION IF NOT EXISTS schema_triggers; + +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA schema_triggers TO public; + +BEGIN; + +-- Table creation +-- { +CREATE OR REPLACE FUNCTION cdb_handle_create_table () +RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$ +DECLARE + event_info RECORD; +BEGIN + event_info := schema_triggers.get_relation_create_eventinfo(); + + -- We're only interested in real relations + IF (event_info.new).relkind != 'r' THEN RETURN; END IF; + + RAISE NOTICE 'Relation % of kind % created in namespace oid %', + event_info.relation, (event_info.new).relkind, (event_info.new).relnamespace; + + -- We don't want to react to alters triggered by superuser, + -- or we'd enter an infinite loop here + IF current_setting('is_superuser') = 'on' THEN + RAISE DEBUG 'no ddl trigger for superuser'; + RETURN; + END IF; + + -- CDB_CartodbfyTable must not create tables, or infinite loop will happen + PERFORM public.CDB_CartodbfyTable(event_info.relation); + +END; $$; +-- } + +-- Column alter +-- { +CREATE OR REPLACE FUNCTION cdb_handle_alter_column () +RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$ +DECLARE + event_info RECORD; + rel RECORD; +BEGIN + event_info := schema_triggers.get_column_alter_eventinfo(); + + SELECT oid,* FROM pg_class WHERE oid = event_info.relation INTO rel; + + RAISE NOTICE 'Column % altered by % (superuser? %) in relation % of kind %', + (event_info.old).attname, current_user, current_setting('is_superuser'), event_info.relation::regclass, rel.relkind; + + -- We're only interested in real relations + IF rel.relkind != 'r' THEN RETURN; END IF; + + -- We don't want to react to alters triggered by superuser, + -- or we'd enter an infinite loop here + IF current_setting('is_superuser') = 'on' THEN + RAISE DEBUG 'no ddl trigger for superuser'; + RETURN; + END IF; + + PERFORM cdb_disable_ddl_hooks(); + + PERFORM public.CDB_CartodbfyTable(event_info.relation); + + PERFORM cdb_enable_ddl_hooks(); + + -- TODO: invalidate varnish ? + +END; $$; +-- } + +-- Column drop +-- { +CREATE OR REPLACE FUNCTION cdb_handle_drop_column () +RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$ +DECLARE + event_info RECORD; + rel RECORD; +BEGIN + event_info := schema_triggers.get_column_drop_eventinfo(); + + SELECT oid,* FROM pg_class WHERE oid = event_info.relation INTO rel; + + RAISE NOTICE 'Column % drop by % (superuser? %) in relation % of kind %', + (event_info.old).attname, current_user, current_setting('is_superuser'), event_info.relation::regclass, rel.relkind; + + -- We're only interested in real relations + IF rel.relkind != 'r' THEN RETURN; END IF; + + -- We don't want to react to drops triggered by superuser, + -- or we'd enter an infinite loop here + IF current_setting('is_superuser') = 'on' THEN + RAISE DEBUG 'no ddl trigger for superuser'; + RETURN; + END IF; + + PERFORM cdb_disable_ddl_hooks(); + + PERFORM public.CDB_CartodbfyTable(event_info.relation); + + PERFORM cdb_enable_ddl_hooks(); + + -- TODO: invalidate varnish ? + +END; $$; +-- } + +-- Column add +-- { +CREATE OR REPLACE FUNCTION cdb_handle_add_column () +RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$ +DECLARE + event_info RECORD; + rel RECORD; +BEGIN + event_info := schema_triggers.get_column_add_eventinfo(); + + SELECT oid,* FROM pg_class WHERE oid = event_info.relation INTO rel; + + RAISE NOTICE 'Column % add by % (superuser? %) in relation % of kind %', + (event_info.old).attname, current_user, current_setting('is_superuser'), event_info.relation::regclass, rel.relkind; + + -- We're only interested in real relations + IF rel.relkind != 'r' THEN RETURN; END IF; + + -- We don't want to react to drops triggered by superuser, + -- or we'd enter an infinite loop here + IF current_setting('is_superuser') = 'on' THEN + RAISE DEBUG 'no ddl trigger for superuser'; + RETURN; + END IF; + + --PERFORM cdb_disable_ddl_hooks(); + --PERFORM public.CDB_CartodbfyTable(event_info.relation); + --PERFORM cdb_enable_ddl_hooks(); + + -- TODO: invalidate varnish ? + +END; $$; +-- } + +CREATE OR REPLACE FUNCTION cdb_disable_ddl_hooks() returns void AS $$ + DROP EVENT TRIGGER IF EXISTS cdb_on_relation_create; + DROP EVENT TRIGGER IF EXISTS cdb_on_alter_column; + DROP EVENT TRIGGER IF EXISTS cdb_on_drop_column; + DROP EVENT TRIGGER IF EXISTS cdb_on_add_column; +$$ LANGUAGE sql; + +CREATE OR REPLACE FUNCTION cdb_enable_ddl_hooks() returns void AS $$ + SELECT cdb_disable_ddl_hooks(); + CREATE EVENT TRIGGER cdb_on_relation_create ON "relation_create" EXECUTE PROCEDURE cdb_handle_create_table(); + CREATE EVENT TRIGGER cdb_on_alter_column ON "column_alter" EXECUTE PROCEDURE cdb_handle_alter_column(); + CREATE EVENT TRIGGER cdb_on_drop_column ON "column_drop" EXECUTE PROCEDURE cdb_handle_drop_column(); + CREATE EVENT TRIGGER cdb_on_add_column ON "column_drop" EXECUTE PROCEDURE cdb_handle_add_column(); +$$ LANGUAGE sql; + +SELECT cdb_enable_ddl_hooks(); + +END; + diff --git a/hook_on_table_create.sql b/hook_on_table_create.sql new file mode 100644 index 0000000..9f87452 --- /dev/null +++ b/hook_on_table_create.sql @@ -0,0 +1,19 @@ +\i cartodb_hooks.sql +\set VERBOSITY terse + +SET SESSION AUTHORIZATION 'development_cartodb_user_1'; + +SELECT session_user, current_user; + + +create schema c; +--create table c.t3(a int); +select 1 as i INTO c.t3; +select * from c.t3; +alter table c.t3 rename column the_geom_webmercator to webmerc; +select * from c.t3; +alter table c.t3 rename column the_geom_webmercator to webmerc2; +select * from c.t3; +alter table c.t3 drop column the_geom_webmercator; +select * from c.t3; +drop schema c cascade;