PostgreSQL create schema from within function trigger - sql

My goal is to create a schema, based on the uuid of a user.
I've therfor wrote a function that gets executed every time a user is created and confirmed.
As the documentation says PostgreSQL Documentation
i may have to write another function that creates a schema because of compatibility.
the 'create_user_schema()' function works in a new query but seems to not work if used in my trigger function. I've tried a lot with casting the uuid to a string but it still don't work.
Did i do something wrong, has this something to do with security and won't work in any case?
CREATE OR REPLACE FUNCTION user_setup() RETURNS trigger AS $user_setup$
DECLARE
s_name uuid := NEW.id;
BEGIN
-- cutout content that works so far
SELECT create_user_schema(CAST(s_name AS TEXT));
RETURN NULL;
END;
$user_setup$ LANGUAGE plpgsql;
CREATE TRIGGER user_setup AFTER INSERT OR UPDATE ON auth.users
FOR EACH ROW EXECUTE FUNCTION user_setup();
CREATE OR REPLACE FUNCTION create_user_schema(s_name text) RETURNS void AS $$
BEGIN
EXECUTE 'CREATE SCHEMA ' || quote_ident(s_name);
END;
$$ LANGUAGE plpgsql;

Well it wasn't really a bug and more some missing piece of information in "how postgres works".
It was necessary to add a 'Security Definer' keyword to the function to let the trigger have the correct privilges on execution.

Related

Understanding the BEFORE UPDATE trigger in SQL

In PostgreSQL, if I want to make changes on the UPDATE command, apparently I should trigger on BEFORE UPDATE. For example:
CREATE OR REPLACE FUNCTION trigger_update_fn() RETURNS trigger AS
$$ BEGIN
new.updated := current_timestamp;
new.created := old.created; -- override changes with original value
RETURN new;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_update
BEFORE UPDATE ON data
FOR EACH ROW
EXECUTE PROCEDURE trigger_update_fn();
In SQL Server there isn’t a BEFORE UPDATE trigger, and you make do with an AFTER UPDATE trigger. The point is that it seems to me that the trigger should work if it’s applied after the update in PostgreSQL, but it doesn’t, of course.
The question is why is the correct trigger a BEFORE UPDATE trigger, and what should I use the AFTER UPDATE trigger for?
The BEFORE trigger can modify the row about to be inserted into the table (NEW). The AFTER trigger runs after the table has been modified, so any changes to NEW have no effect on the persisted data.

How can I catch exceptions within a postgresql function?

I am initializing functions as part of an ETL pipeline; however, one of the functions is dependant to operate on a certain table, which has not yet been created by the time this function has been initialized.
Illustration:
CREATE OR REPLACE FUNCTION some_schema.my_func(parameter_1 BIGINT)
RETURNS TEXT
AS
$$
SELECT foo
FROM non_existent_schema.non_existent_schema AS my_table -- will cause error as this relation does not yet exist
WHERE my_table.bar = parameter_1
;
$$ LANGUAGE sql;
Section 42.6.8 in the documentation (Trapping Errors) discusses exception handling but using BEGIN statements (I am not sure where to include a BEGIN or if it is relevant to my case).
My question is, how can I avoid having this error, and if I would want to silence that Exception, what is the right way to do it.
note: I am a beginner with writing functions in Postgres.
You cannot do that in an SQL function, because SQL does not have procedural code. You need to use a different procedural language, for example PL/pgSQL:
CREATE FUNCTION some_schema.my_func(parameter_1 BIGINT) RETURNS TEXT
LANGUAGE plpgsql AS
$$BEGIN
RETURN (SELECT foo
FROM non_existent_schema.non_existent_schema AS my_table
WHERE my_table.bar = parameter_1);
EXCEPTION
WHEN undefined_table THEN
NULL; -- ignore
END;$$;

Get Table Name of PostgreSQL Event Trigger

I have multiple tables in a PostgreSQL 9.6 database which changes I want to monitor and handle in an extern application.
Handling only data changes wasn't hard, but now I want to monitor structure changes of my database to be stored. This is what I have:
CREATE OR REPLACE FUNCTION log_structureChanged()
RETURNS event_trigger AS $$
BEGIN
UPDATE dbchanged SET changed=2 WHERE table_name = TG_ARGV[0];
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;
CREATE EVENT TRIGGER testData_struc
ON ddl_command_end
WHEN TAG IN ( 'CREATE TABLE', 'ALTER TABLE', 'DROP TABLE' )
EXECUTE PROCEDURE log_structureChanged();
When the EXECUTE PROCEDURE gets called, I want to parse the table that the changes have been made to. The official PostgreSQL documentation didn't really help me - I also may have not fully understood some parts.
So how do I parse the table on that the EVENT TRIGGER fired on? Is it stored inside a variable?
As described in the documentation, you can call the function pg_event_trigger_ddl_commands(), which will return one row per affected object.
You can either use the result column object_identity which contains a textual description of the affected object, or classid and objid, which contain the object ID of the catalog table that contains the object and the object ID of the affected object.

PostgreSQL - Creating a trigger: function does not exist

I'm working on a script for school right now and I've encountered a weird error that I can't fix.
So I've got a playlist, tracks and a playlistInput table.
My task is to create a trigger that if I add/delete a track to my playlist, the amountOfTracks variable should be increased/decreased.
So now to the weird error:
I've made a function "playlistInputAdd" which already works when doing "select playlistInputAdd(1,1)".
The thing is that if I create my trigger, it says that this function doesn't exist. I've seen that someone asked the same question but he didn't add the parameters and I actually did.
The playlistInputAdd function:
CREATE FUNCTION playlistInputAdd(ID int, Amount int)
RETURNS VOID
AS $$
BEGIN
UPDATE playlist
SET amountOfTracks = amountOfTracks + Amount
WHERE playListID = ID;
END;
$$ LANGUAGE plpgsql;
The playlistInputAdd_trigger trigger:
CREATE TRIGGER playlistInputAdd_trigger
AFTER INSERT
ON playlistInput
FOR EACH ROW
EXECUTE PROCEDURE playlistInputAdd(playlistID, 1);
The playlistInputDelete_trigger trigger:
CREATE TRIGGER playlistInputDelete_trigger
AFTER INSERT
ON playlistInput
FOR EACH ROW
EXECUTE PROCEDURE playlistInputAdd(playlistID, 1);
The error message:
ERROR: function playlistinputadd() does not exist
Thank you, in advance!
Trigger functions must be defined with empty argument list and with RETURNS trigger. It is the argument list that causes the error you get.
You can pass arguments to the function in CREATE TRIGGER (even though the argument list has to be empty), but these have to be constants and can be accessed via TG_ARGV in the function body.
You don't need to pass the columns of the modified table as arguments: the row being inserted is available in the NEW variable in the trigger body.
See the documentation for more.

Creating a function in postgresql what return value to use

I'm new to PostgresSQL programming and am trying to create a function called update_docket so that I can call it from an existing stored procedure.
With the help of some great StackOverflow folks I was able to build my update statement as follows:
UPDATE incode_warrants iw
SET warn_docket_no = iv.viol_docket_no
FROM incode_warrantvs iwvs
JOIN incode_violations iv ON iv.viol_citation_no = iwvs.warnv_citation_no
AND iv.viol_viol_no = iwvs.warnv_viol_no
WHERE iw.warn_rid = iwvs.warnv_rid;
In Navicat (My Postgresql interface) I run this query on the database and I get a return message of Affected Rows with a count.
Now I want to take this query and build a function but I'm unsure as to what I should use as the return value. I was guessing at int4, and I tried to build it with return value void but nothing seems to work.
Can someone point me in the right direction of how to create this function so that I can call it from within a very large stored procedure?
I've looked at the Postgresql manual and am admittedly a bit confused and intimidated as I'm not much of a SQL guy.
I believe in the function I need a BEGIN and END for the transaction and I've even tried return 1; but so far I haven't had any luck in successfully saving this function.
Thanks!
Thank you but I am not sure what code you are running. But, if you are doing a generic stored procedure in postgres, you could do something like this:
CREATE OR REPLACE FUNCTION my_function([parameters to be used in stored procedure, if any])
RETURNS boolean AS -- [or you can have it return any data type such as integer]
$BODY$
DECLARE
some_variable text;
some_other_variable integer;
another_variable timestamp;
BEGIN
/*
Put stored procedure here, in this case it would be your update statement
*/
RETURN true; -- or you can return whatever you want based on what you declare above under RETURNS
END; -- closes the BEGIN clause
$BODY$ -- this is simply a delimiter to open and close the actual procedure that runs
LANGUAGE plpgsql;
Hopefully that gives you some idea.... But it would be helpful if you posted whatever you were trying to run.