Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * the PLySubtransaction class
3 : : *
4 : : * src/pl/plpython/plpy_subxactobject.c
5 : : */
6 : :
7 : : #include "postgres.h"
8 : :
9 : : #include "access/xact.h"
10 : : #include "plpy_elog.h"
11 : : #include "plpy_subxactobject.h"
12 : : #include "plpython.h"
13 : : #include "utils/memutils.h"
14 : :
15 : : List *explicit_subtransactions = NIL;
16 : :
17 : :
18 : : static void PLy_subtransaction_dealloc(PyObject *subxact);
19 : : static PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
20 : : static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
21 : :
22 : : static char PLy_subtransaction_doc[] =
23 : : "PostgreSQL subtransaction context manager";
24 : :
25 : : static PyMethodDef PLy_subtransaction_methods[] = {
26 : : {"__enter__", PLy_subtransaction_enter, METH_VARARGS, NULL},
27 : : {"__exit__", PLy_subtransaction_exit, METH_VARARGS, NULL},
28 : : /* user-friendly names for Python <2.6 */
29 : : {"enter", PLy_subtransaction_enter, METH_VARARGS, NULL},
30 : : {"exit", PLy_subtransaction_exit, METH_VARARGS, NULL},
31 : : {NULL, NULL, 0, NULL}
32 : : };
33 : :
34 : : static PyTypeObject PLy_SubtransactionType = {
35 : : PyVarObject_HEAD_INIT(NULL, 0)
36 : : .tp_name = "PLySubtransaction",
37 : : .tp_basicsize = sizeof(PLySubtransactionObject),
38 : : .tp_dealloc = PLy_subtransaction_dealloc,
39 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
40 : : .tp_doc = PLy_subtransaction_doc,
41 : : .tp_methods = PLy_subtransaction_methods,
42 : : };
43 : :
44 : :
45 : : void
4501 peter_e@gmx.net 46 :CBC 23 : PLy_subtransaction_init_type(void)
47 : : {
48 [ - + ]: 23 : if (PyType_Ready(&PLy_SubtransactionType) < 0)
4501 peter_e@gmx.net 49 [ # # ]:UBC 0 : elog(ERROR, "could not initialize PLy_SubtransactionType");
4501 peter_e@gmx.net 50 :CBC 23 : }
51 : :
52 : : /* s = plpy.subtransaction() */
53 : : PyObject *
54 : 29 : PLy_subtransaction_new(PyObject *self, PyObject *unused)
55 : : {
56 : : PLySubtransactionObject *ob;
57 : :
58 : 29 : ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
59 : :
60 [ - + ]: 29 : if (ob == NULL)
4501 peter_e@gmx.net 61 :UBC 0 : return NULL;
62 : :
4501 peter_e@gmx.net 63 :CBC 29 : ob->started = false;
64 : 29 : ob->exited = false;
65 : :
66 : 29 : return (PyObject *) ob;
67 : : }
68 : :
69 : : /* Python requires a dealloc function to be defined */
70 : : static void
71 : 29 : PLy_subtransaction_dealloc(PyObject *subxact)
72 : : {
73 : 29 : }
74 : :
75 : : /*
76 : : * subxact.__enter__() or subxact.enter()
77 : : *
78 : : * Start an explicit subtransaction. SPI calls within an explicit
79 : : * subtransaction will not start another one, so you can atomically
80 : : * execute many SPI calls and still get a controllable exception if
81 : : * one of them fails.
82 : : */
83 : : static PyObject *
84 : 29 : PLy_subtransaction_enter(PyObject *self, PyObject *unused)
85 : : {
86 : : PLySubtransactionData *subxactdata;
87 : : MemoryContext oldcontext;
88 : 29 : PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
89 : :
90 [ + + ]: 29 : if (subxact->started)
91 : : {
92 : 2 : PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
93 : 2 : return NULL;
94 : : }
95 : :
96 [ - + ]: 27 : if (subxact->exited)
97 : : {
4501 peter_e@gmx.net 98 :UBC 0 : PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
99 : 0 : return NULL;
100 : : }
101 : :
4501 peter_e@gmx.net 102 :CBC 27 : subxact->started = true;
103 : 27 : oldcontext = CurrentMemoryContext;
104 : :
105 : : subxactdata = (PLySubtransactionData *)
3083 tgl@sss.pgh.pa.us 106 : 27 : MemoryContextAlloc(TopTransactionContext,
107 : : sizeof(PLySubtransactionData));
108 : :
4501 peter_e@gmx.net 109 : 27 : subxactdata->oldcontext = oldcontext;
110 : 27 : subxactdata->oldowner = CurrentResourceOwner;
111 : :
112 : 27 : BeginInternalSubTransaction(NULL);
113 : :
114 : : /* Be sure that cells of explicit_subtransactions list are long-lived */
3083 tgl@sss.pgh.pa.us 115 : 27 : MemoryContextSwitchTo(TopTransactionContext);
4501 peter_e@gmx.net 116 : 27 : explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
117 : :
118 : : /* Caller wants to stay in original memory context */
3083 tgl@sss.pgh.pa.us 119 : 27 : MemoryContextSwitchTo(oldcontext);
120 : :
4501 peter_e@gmx.net 121 : 27 : Py_INCREF(self);
122 : 27 : return self;
123 : : }
124 : :
125 : : /*
126 : : * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
127 : : *
128 : : * Exit an explicit subtransaction. exc_type is an exception type, exc
129 : : * is the exception object, tb is the traceback. If exc_type is None,
130 : : * commit the subtransaction, if not abort it.
131 : : *
132 : : * The method signature is chosen to allow subtransaction objects to
133 : : * be used as context managers as described in
134 : : * <http://www.python.org/dev/peps/pep-0343/>.
135 : : */
136 : : static PyObject *
137 : 25 : PLy_subtransaction_exit(PyObject *self, PyObject *args)
138 : : {
139 : : PyObject *type;
140 : : PyObject *value;
141 : : PyObject *traceback;
142 : : PLySubtransactionData *subxactdata;
143 : 25 : PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
144 : :
145 [ - + ]: 25 : if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
4501 peter_e@gmx.net 146 :UBC 0 : return NULL;
147 : :
4501 peter_e@gmx.net 148 [ + + ]:CBC 25 : if (!subxact->started)
149 : : {
150 : 2 : PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
151 : 2 : return NULL;
152 : : }
153 : :
154 [ + + ]: 23 : if (subxact->exited)
155 : : {
156 : 2 : PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
157 : 2 : return NULL;
158 : : }
159 : :
160 [ - + ]: 21 : if (explicit_subtransactions == NIL)
161 : : {
4501 peter_e@gmx.net 162 :UBC 0 : PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
163 : 0 : return NULL;
164 : : }
165 : :
4501 peter_e@gmx.net 166 :CBC 21 : subxact->exited = true;
167 : :
168 [ + + ]: 21 : if (type != Py_None)
169 : : {
170 : : /* Abort the inner transaction */
171 : 11 : RollbackAndReleaseCurrentSubTransaction();
172 : : }
173 : : else
174 : : {
175 : 10 : ReleaseCurrentSubTransaction();
176 : : }
177 : :
178 : 21 : subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
179 : 21 : explicit_subtransactions = list_delete_first(explicit_subtransactions);
180 : :
181 : 21 : MemoryContextSwitchTo(subxactdata->oldcontext);
182 : 21 : CurrentResourceOwner = subxactdata->oldowner;
3083 tgl@sss.pgh.pa.us 183 : 21 : pfree(subxactdata);
184 : :
2389 peter_e@gmx.net 185 : 21 : Py_RETURN_NONE;
186 : : }
|