]> begriffs open source - ai-pg/blob - full-docs/txt/plpython-subtransaction.txt
Convert HTML docs to more streamlined TXT
[ai-pg] / full-docs / txt / plpython-subtransaction.txt
1
2 44.7. Explicit Subtransactions #
3
4    44.7.1. Subtransaction Context Managers
5
6    Recovering from errors caused by database access as described in
7    Section 44.6.2 can lead to an undesirable situation where some
8    operations succeed before one of them fails, and after recovering from
9    that error the data is left in an inconsistent state. PL/Python offers
10    a solution to this problem in the form of explicit subtransactions.
11
12 44.7.1. Subtransaction Context Managers #
13
14    Consider a function that implements a transfer between two accounts:
15 CREATE FUNCTION transfer_funds() RETURNS void AS $$
16 try:
17     plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_name
18  = 'joe'")
19     plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_name
20  = 'mary'")
21 except plpy.SPIError as e:
22     result = "error transferring funds: %s" % e.args
23 else:
24     result = "funds transferred correctly"
25 plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
26 plpy.execute(plan, [result])
27 $$ LANGUAGE plpython3u;
28
29    If the second UPDATE statement results in an exception being raised,
30    this function will report the error, but the result of the first UPDATE
31    will nevertheless be committed. In other words, the funds will be
32    withdrawn from Joe's account, but will not be transferred to Mary's
33    account.
34
35    To avoid such issues, you can wrap your plpy.execute calls in an
36    explicit subtransaction. The plpy module provides a helper object to
37    manage explicit subtransactions that gets created with the
38    plpy.subtransaction() function. Objects created by this function
39    implement the context manager interface. Using explicit subtransactions
40    we can rewrite our function as:
41 CREATE FUNCTION transfer_funds2() RETURNS void AS $$
42 try:
43     with plpy.subtransaction():
44         plpy.execute("UPDATE accounts SET balance = balance - 100 WHERE account_
45 name = 'joe'")
46         plpy.execute("UPDATE accounts SET balance = balance + 100 WHERE account_
47 name = 'mary'")
48 except plpy.SPIError as e:
49     result = "error transferring funds: %s" % e.args
50 else:
51     result = "funds transferred correctly"
52 plan = plpy.prepare("INSERT INTO operations (result) VALUES ($1)", ["text"])
53 plpy.execute(plan, [result])
54 $$ LANGUAGE plpython3u;
55
56    Note that the use of try/except is still required. Otherwise the
57    exception would propagate to the top of the Python stack and would
58    cause the whole function to abort with a PostgreSQL error, so that the
59    operations table would not have any row inserted into it. The
60    subtransaction context manager does not trap errors, it only assures
61    that all database operations executed inside its scope will be
62    atomically committed or rolled back. A rollback of the subtransaction
63    block occurs on any kind of exception exit, not only ones caused by
64    errors originating from database access. A regular Python exception
65    raised inside an explicit subtransaction block would also cause the
66    subtransaction to be rolled back.