2 * the PLySubtransaction class
4 * src/pl/plpython/plpy_subxactobject.c
9 #include "access/xact.h"
10 #include "plpy_elog.h"
11 #include "plpy_subxactobject.h"
13 #include "utils/memutils.h"
15 List
*explicit_subtransactions
= NIL
;
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
);
22 static char PLy_subtransaction_doc
[] =
23 "PostgreSQL subtransaction context manager";
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
},
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
,
46 PLy_subtransaction_init_type(void)
48 if (PyType_Ready(&PLy_SubtransactionType
) < 0)
49 elog(ERROR
, "could not initialize PLy_SubtransactionType");
52 /* s = plpy.subtransaction() */
54 PLy_subtransaction_new(PyObject
*self
, PyObject
*unused
)
56 PLySubtransactionObject
*ob
;
58 ob
= PyObject_New(PLySubtransactionObject
, &PLy_SubtransactionType
);
66 return (PyObject
*) ob
;
69 /* Python requires a dealloc function to be defined */
71 PLy_subtransaction_dealloc(PyObject
*subxact
)
76 * subxact.__enter__() or subxact.enter()
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
84 PLy_subtransaction_enter(PyObject
*self
, PyObject
*unused
)
86 PLySubtransactionData
*subxactdata
;
87 MemoryContext oldcontext
;
88 PLySubtransactionObject
*subxact
= (PLySubtransactionObject
*) self
;
92 PLy_exception_set(PyExc_ValueError
, "this subtransaction has already been entered");
98 PLy_exception_set(PyExc_ValueError
, "this subtransaction has already been exited");
102 subxact
->started
= true;
103 oldcontext
= CurrentMemoryContext
;
105 subxactdata
= (PLySubtransactionData
*)
106 MemoryContextAlloc(TopTransactionContext
,
107 sizeof(PLySubtransactionData
));
109 subxactdata
->oldcontext
= oldcontext
;
110 subxactdata
->oldowner
= CurrentResourceOwner
;
112 BeginInternalSubTransaction(NULL
);
114 /* Be sure that cells of explicit_subtransactions list are long-lived */
115 MemoryContextSwitchTo(TopTransactionContext
);
116 explicit_subtransactions
= lcons(subxactdata
, explicit_subtransactions
);
118 /* Caller wants to stay in original memory context */
119 MemoryContextSwitchTo(oldcontext
);
126 * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
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.
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/>.
137 PLy_subtransaction_exit(PyObject
*self
, PyObject
*args
)
142 PLySubtransactionData
*subxactdata
;
143 PLySubtransactionObject
*subxact
= (PLySubtransactionObject
*) self
;
145 if (!PyArg_ParseTuple(args
, "OOO", &type
, &value
, &traceback
))
148 if (!subxact
->started
)
150 PLy_exception_set(PyExc_ValueError
, "this subtransaction has not been entered");
156 PLy_exception_set(PyExc_ValueError
, "this subtransaction has already been exited");
160 if (explicit_subtransactions
== NIL
)
162 PLy_exception_set(PyExc_ValueError
, "there is no subtransaction to exit from");
166 subxact
->exited
= true;
170 /* Abort the inner transaction */
171 RollbackAndReleaseCurrentSubTransaction();
175 ReleaseCurrentSubTransaction();
178 subxactdata
= (PLySubtransactionData
*) linitial(explicit_subtransactions
);
179 explicit_subtransactions
= list_delete_first(explicit_subtransactions
);
181 MemoryContextSwitchTo(subxactdata
->oldcontext
);
182 CurrentResourceOwner
= subxactdata
->oldowner
;