Search Postgresql Archives

ROLLBACK in a function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



How can I write a PL/PgSQL function that rolls back every database change it has done?

 

I’m about to write a set of database test functions.  Each function needs to do some INSERT, UPDATE, or DELETE actions, test whether they had their intended effect, and then roll back the test changes to restore the database to its prior state.  Here’s a simple example:

 

CREATE OR REPLACE FUNCTION tests.person() RETURNS varchar AS

$BODY$

DECLARE

          errs VARCHAR = '';

          -- Test declarations:

          old_count BIGINT;

          new_count BIGINT;

BEGIN

--       RAISE EXCEPTION '';

-- EXCEPTION

--       WHEN raise_exception THEN

          SAVEPOINT s;

          SET search_path TO public, tests;

          -- Test code:

                   SELECT count(*) INTO old_count FROM person_i;

                   INSERT INTO person (last_name) VALUES ('_test');

                   SELECT count(*) INTO new_count FROM person_i;

                   IF NOT new_count = old_count + 1 THEN

                             errs := errs || ': Failed to insert into ''person'';

                   END IF;

          ROLLBACK TO SAVEPOINT s;

          RETURN errs;

END;

$BODY$

LANGUAGE plpgsql VOLATILE

;

When I run this function, I get this error:

 

ERROR: SPI_execute_plan failed executing query "SAVEPOINT s": SPI_ERROR_TRANSACTION

SQL state: XX000

Context: PL/pgSQL function "person" line 11 at SQL statement

 

I tried another way to make the rollback happen: The last paragraph of http://www.postgresql.org/docs/8.3/static/plpgsql-structure.html said “a block containing an EXCEPTION clause effectively forms a subtransaction that can be rolled back without affecting the outer transaction.”  So I rewrote the test function like this:

 

CREATE OR REPLACE FUNCTION tests.person() RETURNS varchar AS

$BODY$

DECLARE

          errs VARCHAR = '';

          -- Test declarations:

          old_count BIGINT;

          new_count BIGINT;

BEGIN

          RAISE EXCEPTION '';

EXCEPTION

          WHEN raise_exception THEN

                   SET search_path TO public, tests;

                   -- Test code:

                             SELECT count(*) INTO old_count FROM person_i;

                             INSERT INTO person (last_name) VALUES ('_test');

                             SELECT count(*) INTO new_count FROM person_i;

                             IF NOT new_count = old_count + 1 THEN

                                      errs := errs || ': Failed to insert into ''person''’;

                             END IF;

                   RETURN errs;

END;

$BODY$

LANGUAGE plpgsql VOLATILE

;

 

The function runs OK, but it does not roll back the actions it did (in this case, the INSERT).

 

~ TIA

~ Ken

 

 


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux