I want to use savepoint feature inside a function in PostgreSQL. I read that savepoint cannot be used inside functions in Postgres.
But while I rollback, I want to rollback to a specific point because of which I want to use savepoint. What is the alternative way to do it?
Sample Code
CREATE or replace FUNCTION fn_loadData_Subha()
RETURNS BIGINT
AS
$$
DECLARE
batchId BIGINT;
currentTime TIMESTAMP;
processName VARCHAR(20);
BEGIN
-- Getting current date and time
select TIMESTAMP 'NOW' into currentTime;
select 'ETL_Subha' INTO processName;
SAVEPOINT first_savepoint;
-- Inserting new record into batch log table
INSERT INTO TB_HSS_BATCH_LOG
(PROCESS_NAME,START_DATE,STATUS)
SELECT processName,currentTime,'STARTED';
select currval('TB_HSS_BATCH_LOG_id_seq') INTO batchId;
-- Inserting cost data to history table
Insert into tb_hss_procedure_cost_hist1
(HOSP_SYSTEM, HOSP_FACILITY, surgeon_name, procedure_name, department, current_dept_rank, no_of_surgeons, current_imp_cost
, current_med_surg_cost, current_total_cost, annual_volume, sys_pref_cost,load_seq_no, CREATED_AT)
Select
HOSP_SYSTEM, HOSP_FACILITY,surgeon_name,procedure_name,department,current_dept_rank, no_of_surgeons, current_imp_cost
, current_med_surg_cost, current_total_cost, annual_volume, sys_pref_cost, batchId,currentTime
from tb_hss_procedure_cost_stag_in;
RELEASE SAVEPOINT first_savepoint;
RETURN 1;
EXCEPTION
WHEN PLPGSQL_ERROR THEN
RAISE EXCEPTION '% %', SQLERRM, SQLSTATE;
RAISE NOTICE '% %', SQLERRM, SQLSTATE;
RETURN 0;
WHEN OTHERS THEN
RAISE EXCEPTION '% %', SQLERRM, SQLSTATE;
RAISE NOTICE '% %', SQLERRM, SQLSTATE;
RETURN 0;
ROLLBACK TRANSACTION;
END;
$$LANGUAGE plpgsql;
The way to use savepoints in PL/pgSQL functions is to use a BEGIN ... EXCEPTION ... END
block. Under the hood, this sets a savepoint at BEGIN
and rolls back to it when an exception is encountered.
So your code could look like that (I'm not 100% sure if I read your code correctly):
DECLARE
batchid bigint;
processname varchar(20) := 'ETL_Subha';
BEGIN
BEGIN
INSERT INTO TB_HSS_BATCH_LOG
(PROCESS_NAME,START_DATE,STATUS)
VALUES (processname,current_timestamp,'STARTED')
RETURNING id INTO batchid;
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
END;
Some general remarks to your code:
batchid
is never used.currenttime
is unnecessary – every call to current_time
will return the same value in a transaction.RAISE
will terminate execution. If you want an error to be thrown, just don't catch the original exception; it will be more meaningful than your exception. My code above assumes that you want to catch the exception and want to return 0 instead.SELECT val INTO variable
is the same as variable := value
under the hood, but the latter is generally considered more readable.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With