]> begriffs open source - ai-pg/blob - full-docs/txt/pltcl-subtransactions.txt
Convert HTML docs to more streamlined TXT
[ai-pg] / full-docs / txt / pltcl-subtransactions.txt
1
2 42.9. Explicit Subtransactions in PL/Tcl #
3
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.
9
10    Consider a function that implements a transfer between two accounts:
11 CREATE FUNCTION transfer_funds() RETURNS void AS $$
12     if [catch {
13         spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_name
14  = 'joe'"
15         spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_name
16  = 'mary'"
17     } errormsg] {
18         set result [format "error transferring funds: %s" $errormsg]
19     } else {
20         set result "funds transferred successfully"
21     }
22     spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
23 $$ LANGUAGE pltcl;
24
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.
31
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
35    our function as:
36 CREATE FUNCTION transfer_funds2() RETURNS void AS $$
37     if [catch {
38         subtransaction {
39             spi_exec "UPDATE accounts SET balance = balance - 100 WHERE account_
40 name = 'joe'"
41             spi_exec "UPDATE accounts SET balance = balance + 100 WHERE account_
42 name = 'mary'"
43         }
44     } errormsg] {
45         set result [format "error transferring funds: %s" $errormsg]
46     } else {
47         set result "funds transferred successfully"
48     }
49     spi_exec "INSERT INTO operations (result) VALUES ('[quote $result]')"
50 $$ LANGUAGE pltcl;
51
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
57    an error is reported.
58
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.