Fix header inclusion order in c.h.
[pgsql.git] / src / pl / plpython / plpy_subxactobject.c
blob5c92a0e089a1b214e61178328047ceaa534286d0
1 /*
2 * the PLySubtransaction class
4 * src/pl/plpython/plpy_subxactobject.c
5 */
7 #include "postgres.h"
9 #include "access/xact.h"
10 #include "plpy_elog.h"
11 #include "plpy_subxactobject.h"
12 #include "plpython.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},
31 {NULL, NULL, 0, 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,
45 void
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() */
53 PyObject *
54 PLy_subtransaction_new(PyObject *self, PyObject *unused)
56 PLySubtransactionObject *ob;
58 ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
60 if (ob == NULL)
61 return NULL;
63 ob->started = false;
64 ob->exited = false;
66 return (PyObject *) ob;
69 /* Python requires a dealloc function to be defined */
70 static void
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
81 * one of them fails.
83 static PyObject *
84 PLy_subtransaction_enter(PyObject *self, PyObject *unused)
86 PLySubtransactionData *subxactdata;
87 MemoryContext oldcontext;
88 PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
90 if (subxact->started)
92 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
93 return NULL;
96 if (subxact->exited)
98 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
99 return NULL;
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);
121 Py_INCREF(self);
122 return self;
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/>.
136 static PyObject *
137 PLy_subtransaction_exit(PyObject *self, PyObject *args)
139 PyObject *type;
140 PyObject *value;
141 PyObject *traceback;
142 PLySubtransactionData *subxactdata;
143 PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
145 if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
146 return NULL;
148 if (!subxact->started)
150 PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
151 return NULL;
154 if (subxact->exited)
156 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
157 return NULL;
160 if (explicit_subtransactions == NIL)
162 PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
163 return NULL;
166 subxact->exited = true;
168 if (type != Py_None)
170 /* Abort the inner transaction */
171 RollbackAndReleaseCurrentSubTransaction();
173 else
175 ReleaseCurrentSubTransaction();
178 subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
179 explicit_subtransactions = list_delete_first(explicit_subtransactions);
181 MemoryContextSwitchTo(subxactdata->oldcontext);
182 CurrentResourceOwner = subxactdata->oldowner;
183 pfree(subxactdata);
185 Py_RETURN_NONE;