PostgreSQL: How to automatically set table owner when creating new table - postgresql

In PostgreSQL, table owner is automatically set to user who created the table when creating new table. In this situation, the other users can not dropped the table.
So I want to automatically change table owner for newly created tables to specific role. By using this approach, anyone who has this role can drop the tables which table owner is the same role.
To achieve this goal, I used the same approach as described in this blog. https://blog.hagander.net/setting-owner-at-create-table-237/
I am currently using this function. This function should be triggered when new table is created in a schema analytics_custom and change table owner to analytics_custom_readwrite.
But it looks like the functions is not working as expected. Table owner of newly created table is an user who created the table.
Am I missing something? Any problem with this function?
CREATE OR REPLACE FUNCTION analytics_custom.trg_create_set_owner()
RETURNS event_trigger
LANGUAGE plpgsql
AS $function$
DECLARE
obj record;
BEGIN
FOR obj IN
SELECT *
FROM pg_event_trigger_ddl_commands()
WHERE schema_name='analytics_custom' AND command_tag='CREATE TABLE'
LOOP
if obj.object_identity ~ 'analytics_custom.*'
THEN
EXECUTE format('ALTER TABLE %s OWNER TO analytics_custom_readwrite', obj.object_identity);
end if;
END LOOP;
END;
$function$
;
CREATE EVENT TRIGGER analytics_custom_trg_create_set_owner
ON ddl_command_end
WHEN tag IN ('CREATE TABLE')
EXECUTE PROCEDURE analytics_custom.trg_create_set_owner();

Related

How to create a trigger in postgresql

I need to create a trigger in postgres where, when I add a record to table A, it automatically inserts its primary key value (which is auto incremented) into table B, the primary key of table A is the foreign key in table B.
I have tried doing it through pgadmin but it does not allow me to save. Could someone help out please.
First create the following trigger function.
CREATE OR REPLACE FUNCTION auto_insert() RETURNS TRIGGER AS
$BODY$
BEGIN
INSERT INTO
B(a_id)
VALUES(new.id);
RETURN new;
END;
$BODY$
language plpgsql;
And then attach the trigger function to table A.
CREATE TRIGGER auto_inserter
AFTER INSERT ON A
FOR EACH ROW
EXECUTE PROCEDURE auto_insert();

how to write trigger which will generate new schema for new department entry?

I have to write a trigger that will generate a new schema and in each schema, there should be two fixed tables.
when a new department will be registered the trigger should make a new schema and also it should make the same two tables in every schema with their constraints.
That could be a simple row level trigger:
CREATE FUNCTION make_schema() RETURNS trigger
LANGUAGE plpgsql AS
$$BEGIN
EXECUTE format('CREATE SCHEMA %I', NEW.department_name);
EXECUTE format ('CREATE TABLE %I.tab1 (...)', NEW.department_name);
END;$$;
CREATE TRIGGER make_schema AFTER INSERT ON department_registration
FOR EACH ROW EXECUTE PROCEDURE make_schema();

Transitive/nested permissions in PostgreSQL

I have the following setup:
create role test_user noinherit nologin;
create table test_me ( attr text );
create view v_test_me as select * from test_me;
create function fn() returns trigger language plpgsql as $$
begin
insert into test_me(attr) values (NEW.attr);
return NEW;
end; $$;
create trigger tg instead of insert on v_test_me
for each row execute procedure fn();
grant insert on v_test_me to test_user;
set role test_user;
insert into v_test_me(attr) values ('hello?');
Here I have a table and a view on top of it. The view has an instead-of-trigger. I am allowing test_user to insert into the view. But i get the following error:
ERROR: permission denied for table test_me
CONTEXT: SQL statement "insert into test_me(attr) values (NEW.attr)"
It looks like I do not have permission to execute an insert statement on the test_me table, which is expected. Is there any way I can allow user to insert into test_me table without directly granting them such permission?
In this case a SECURITY DEFINER modifier on the trigger function fn() will solve the issue. As per CREATE FUNCTION documentation:
SECURITY DEFINER specifies that the function is to be executed with
the privileges of the user that created it
This will allow inserting into test_me table, provided the owner of the function has such permission.

Can event triggers be used to alter the owner of a newly created table to a role the creator is not a member of?

I want to alter the owner of a postgreSQL table upon creation. So far so good.
CREATE OR REPLACE FUNCTION trg_create_set_table_owner()
RETURNS event_trigger
LANGUAGE plpgsql
AS $$
DECLARE
obj record;
BEGIN
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() WHERE command_tag='CREATE TABLE' LOOP
EXECUTE format('ALTER TABLE %s OWNER TO blubb', obj.object_identity);
END LOOP;
END;
$$;
However, I would like to change the owner to a role that the user creating the table is not a part of. Is that possible at all?
https://www.postgresql.org/docs/current/static/sql-createfunction.html#SECURITY DEFINER
Because a SECURITY DEFINER function is executed with the privileges of
the user that owns it, care is needed to ensure that the function
cannot be misused
Apart of this - just create a function with SU that will accept tablename and rolename as arguments and will run ALTER TABLE. grant execute to the role, consuming trg_create_set_table_owner and it will work. But the concern that the role can use the ability to alter table outside of trg_create_set_table_owner remains...
Of course you can check the possible role names and table names from a list of allowed before passing them to execute format('ALTER TABLE %I OWNER TO %I')

How to use the auto-generated primary key in the same row postrges

I am trying to make an insert statement into a table with the following schema
CREATE TABLE auth(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
role VARCHAR(64)
);
I am using pgcrypto extension to generate uuids. Is it possible to append id to the role field while inserting a row in this table?
I am inserting in this table using
insert into auth (role) values ('admin');
I want to append the id generated to admin so that the role would look something like admin_12234-3453-3453-345-34534.
You need an insert trigger to do this:
CREATE FUNCTION admin_uuid() RETURNS trigger AS $$
BEGIN
NEW.role := NEW.role || NEW.id::text;
RETURN NEW;
END;
$$ LANGUAGE plpgsql STABLE;
CREATE TRIGGER set_admin_uuid
BEFORE INSERT ON auth
FOR EACH ROW EXECUTE PROCEDURE admin_uuid();
I think there is no direct way to achieve this. But postgres allows defining rules on tables and views (see https://www.postgresql.org/docs/9.2/static/sql-createrule.html). You can create a new rule for insertion which creates the id and the role as desired.