Error handling in redshift stored procedures - amazon-redshift

When I tried to add exception handling in redshift stored procedure getting below error.
Please find the code below:
CREATE TABLE employee (firstname varchar, lastname varchar);
INSERT INTO employee VALUES ('Tomas','Smith');
CREATE TABLE employee_error_log (message varchar);
CREATE OR REPLACE PROCEDURE update_employee_sp() AS
$$
BEGIN
UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith';
EXECUTE 'select invalid';
EXCEPTION WHEN OTHERS THEN
RAISE INFO 'An exception occurred.';
INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM);
END;
$$
LANGUAGE plpgsql;
Error: Amazon invalid operation: ROLLBACK cannot be invoked from a procedure that is executing in an atomic context.
Anyone please provide the solution here.
One more query in redshift is how we can log an error message and error code in table. For example how we can log a DML or DDL errors in some table which occurs inside the stored procedure. Any system table available for getting error code and error message of DML errors like error_messages table in teradata.

Change the connection to autocommit=true. It will work.

Related

Triggers in Liquibase

I am using postgresql and I two tables customer (id , name, address, city) and update_customer(id, time). When ever I insert a new value in customer table I want to store that id and time in update_customer table. But I am currently getting an exception and I dont have an idea about what went wrong.
code:
<changeSet author="newUser" id="03">
<sql>
CREATE TRIGGER customer_trigger
AFTER INSERT ON customer
FOR EACH ROW
EXECUTE PROCEDURE customer_update();
CREATE FUNCTION customer_update() RETURNS trigger AS $example_table$
BEGIN
INSERT INTO update_customer(id,time) VALUES (NEW.id , current_timestamp);
RETURN NEW;
END;
</sql>
</changeSet>
error
Caused by: liquibase.exception.LiquibaseException: liquibase.exception.MigrationFailedException: Migration failed for change set db/changelog/trigger.xml::03::newUser:
Using 'createProcedure' tag did the trick for me, I dont why while using 'sql' tag Liquibase kept on throwing errors saying something is wrong near Insert.

PSQL Stored Procedure IF Statement Syntax Error (v13.2)

TLDR: Getting a SYNTAX ERROR at 'IF'
I'm trying to create a stored procedure that checks for unique display_name before attempting an insert and I'm getting a syntax error at 'IF' when trying to create via PSQL in PowerShell. I've read the official documentation, checked multiple tutorials, and looked on here (StackOverflow). Any idea what the issue is?
FWIW: I am most familiar with MariaDB.
CREATE PROCEDURE sp_create_user (
a_username VARCHAR(255)
,a_password VARCHAR(200)
,a_display_name VARCHAR(20)
)
LANGUAGE SQL
AS $$
IF EXISTS(SELECT id FROM users WHERE display_name = a_display_name) THEN
raise exception 'duplicate display_name: %', a_display_name using hint = 'enter a different display_name';
END IF;
INSERT INTO users (username, password, display_name)
VALUES (a_username, a_password, a_display_name)
RETURNING id, username, display_name;
$$;

Error while using Trigger in Greenplum

If any of you created/tried Triggers on Greenplum, Please help me to resolve this
I have a table where a "id" column has some value, and i want to put a trigger
Before insert any data in this table, it should call a function/trigger to check
a) if the data is available for "id" in Parent table or not
b) there is already a row available for given "id"
--Table DDL
create table test_trigger(id integer, details text);
--Trigger Function
create or replace function insert_row_trigger() returns trigger as $$
begin
if exists (SELECT 1 FROM test_trigger WHERE id = NEW.id)
Then
Return NULL;
else
Return NEW;
End If;
End;
$$ language plpgsql;
--Trigger Creation
create trigger my_trigger before insert on test_trigger for each row execute procedure insert_row_trigger();
--Drop Trigger
drop trigger my_trigger on test_trigger
ERROR
ERROR: function cannot execute on segment because it accesses
relation "jiodba.test_trigger" (functions.c:151) (seg1
SRDCB0002GPM02:40001 pid=11366) (cdbdisp.c:1477) DETAIL: SQL
statement "SELECT exists (SELECT 1 FROM test_trigger WHERE id = $1 )"
PL/pgSQL function "insert_row_trigger" line 2 at if
********** Error **********
ERROR: function cannot execute on segment because it accesses relation
"jiodba.test_trigger" (functions.c:151) (seg1 SRDCB0002GPM02:40001
pid=11366) (cdbdisp.c:1477) SQL state: XX000 Detail: SQL statement
"SELECT exists (SELECT 1 FROM test_trigger WHERE id = $1 )" PL/pgSQL
function "insert_row_trigger" line 2 at if
Please help me on this.
~I also read somewhere that triggers are not supported in GP
Trigger is a function executed on the segment level for each of the input data rows. The issue is that in Greenplum you cannot execute any query from the segment level as it would require each segment to reconnect to the master to execute it separately, which will cause a connection bloat for a big systems.
The way to overcome this is for instance this way:
Have an unique index on the Parent table
In a single transaction, execute two statements: first, insert into parent select all the rows that does not exist in parent table. Second, insert into target table all the input rows with the keys just inserted to the parent table.
In general, you will have the same logic, but without trigger
Create a RULE statement is a alternative to triggers in GP.
Try this:
https://gpdb.docs.pivotal.io/5280/ref_guide/sql_commands/CREATE_RULE.html#:~:text=The%20Greenplum%20Database%20rule%20system,used%20on%20views%20as%20well.

Postgres trigger syntax

Using SQLFiddle, PostgreSQL 9.3.1.
I am learning to define triggers in PostgreSQL, and after doing some research I've found out the following:
Triggers in Postgres are different from MYSQL. Where in Postgres you must create a function that RETURNS TRIGGER, in MySQL you can just create a trigger. So this is what I've come up with:
On Employee Insert, we want to update Departments Total Salary.
CREATE FUNCTION update_sal() RETURNS TRIGGER AS $$
BEGIN
IF NEW.dno IS NOT NULL THEN
UPDATE Department SET Total_sal = total_sal + NEW.salary
WHERE department.dno = NEW.dno;
END IF;
RETURN NULL;
END;
$$ Language plpgsql;
CREATE TRIGGER updateInsert
AFTER INSERT ON Employee
FOR EACH ROW
EXECUTE PROCEDURE update_sal();
And I'm getting the following error:
Schema Creation Failed: ERROR: unterminated dollar-quoted string at or near "$$
BEGIN IF NEW.dno IS NOT NULL THEN UPDATE Department
SET Total_sal = total_sal +NEW.salary WHERE department.dno = NEW.dno":
I've solved the issue thanks to Database Function giving an error - Postgresql
It seems just changing the query terminator at the bottom of the Scheme Window solves this issue.
If you copy-pasted the code, then you've got a simple syntax error: ENDl should be END; in the last-but-one line of the function definition.
Otherwise, it looks good to me.

Custom error message for postgresql check constrint

I have the "valid_id" check constraint on my requests table. But when it violates the constraint it shows following error
ERROR: new row for relation "requests" violates check constraint
"valid_name" DETAIL: Failing row contains ....
But instead of that I want to show message like "Failed to insert record. name is required".
Is there any way to show the custom error message in PostgreSQL?
This is kind of advanced territory here because you want to be pretty familiar with SQL states as well as existing error messages before you get started. Note that you want to re-used existing sql states as appropriate so that the application doesn't know you have overridden your check constraint.
But what you can do is create a function which runs the check and issues a raise exception if the check fails. Something like:
CREATE FUNCTION check_is_not_null(value text, column_name text) RETURNS BOOL
LANGUAGE plpgsql AS $$
begin
IF $1 IS NULL THEN
RAISE EXCEPTION 'Error: % is required', $2;
END IF;
RETURN TRUE;
END;
$$;
If you are using 8.4 or higher, you can specify an SQL state.