2 42.9. Explicit Subtransactions in PL/Tcl #
4 Recovering from errors caused by database access as described in
5 Section 42.8 can lead to an undesirable situation where some operations
6 succeed before one of them fails, and after recovering from that error
7 the data is left in an inconsistent state. PL/Tcl offers a solution to
8 this problem in the form of explicit subtransactions.
10 Consider a function that implements a transfer between two accounts:
11 CREATE FUNCTION transfer_funds() RETURNS void AS $$
13 spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_name
15 spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_name
18 set result [format "error transferring funds: %s" $errormsg]
20 set result "funds transferred successfully"
22 spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
25 If the second UPDATE statement results in an exception being raised,
26 this function will log the failure, but the result of the first UPDATE
27 will nevertheless be committed. In other words, the funds will be
28 withdrawn from Joe's account, but will not be transferred to Mary's
29 account. This happens because each spi_exec is a separate
30 subtransaction, and only one of those subtransactions got rolled back.
32 To handle such cases, you can wrap multiple database operations in an
33 explicit subtransaction, which will succeed or roll back as a whole.
34 PL/Tcl provides a subtransaction command to manage this. We can rewrite
36 CREATE FUNCTION transfer_funds2() RETURNS void AS $$
39 spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_
41 spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_
45 set result [format "error transferring funds: %s" $errormsg]
47 set result "funds transferred successfully"
49 spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
52 Note that use of catch is still required for this purpose. Otherwise
53 the error would propagate to the top level of the function, preventing
54 the desired insertion into the operations table. The subtransaction
55 command does not trap errors, it only assures that all database
56 operations executed inside its scope will be rolled back together when
59 A rollback of an explicit subtransaction occurs on any error reported
60 by the contained Tcl code, not only errors originating from database
61 access. Thus a regular Tcl exception raised inside a subtransaction
62 command will also cause the subtransaction to be rolled back. However,
63 non-error exits out of the contained Tcl code (for instance, due to
64 return) do not cause a rollback.