PostgreSQL Source Code git master
plpy_subxactobject.c
Go to the documentation of this file.
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
16
17
18static void PLy_subtransaction_dealloc(PyObject *subxact);
19static PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
20static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
21
23"PostgreSQL subtransaction context manager";
24
25static 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
34static 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
45void
47{
48 if (PyType_Ready(&PLy_SubtransactionType) < 0)
49 elog(ERROR, "could not initialize PLy_SubtransactionType");
50}
51
52/* s = plpy.subtransaction() */
53PyObject *
54PLy_subtransaction_new(PyObject *self, PyObject *unused)
55{
57
59
60 if (ob == NULL)
61 return NULL;
62
63 ob->started = false;
64 ob->exited = false;
65
66 return (PyObject *) ob;
67}
68
69/* Python requires a dealloc function to be defined */
70static void
72{
73}
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 */
83static PyObject *
84PLy_subtransaction_enter(PyObject *self, PyObject *unused)
85{
86 PLySubtransactionData *subxactdata;
87 MemoryContext oldcontext;
89
90 if (subxact->started)
91 {
92 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
93 return NULL;
94 }
95
96 if (subxact->exited)
97 {
98 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
99 return NULL;
100 }
101
102 subxact->started = true;
103 oldcontext = CurrentMemoryContext;
104
105 subxactdata = (PLySubtransactionData *)
107 sizeof(PLySubtransactionData));
108
109 subxactdata->oldcontext = oldcontext;
110 subxactdata->oldowner = CurrentResourceOwner;
111
113
114 /* Be sure that cells of explicit_subtransactions list are long-lived */
117
118 /* Caller wants to stay in original memory context */
119 MemoryContextSwitchTo(oldcontext);
120
121 Py_INCREF(self);
122 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 */
136static PyObject *
137PLy_subtransaction_exit(PyObject *self, PyObject *args)
138{
139 PyObject *type;
140 PyObject *value;
141 PyObject *traceback;
142 PLySubtransactionData *subxactdata;
144
145 if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
146 return NULL;
147
148 if (!subxact->started)
149 {
150 PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
151 return NULL;
152 }
153
154 if (subxact->exited)
155 {
156 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
157 return NULL;
158 }
159
161 {
162 PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
163 return NULL;
164 }
165
166 subxact->exited = true;
167
168 if (type != Py_None)
169 {
170 /* Abort the inner transaction */
172 }
173 else
174 {
176 }
177
180
181 MemoryContextSwitchTo(subxactdata->oldcontext);
182 CurrentResourceOwner = subxactdata->oldowner;
183 pfree(subxactdata);
184
185 Py_RETURN_NONE;
186}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
static struct @162 value
List * list_delete_first(List *list)
Definition: list.c:943
List * lcons(void *datum, List *list)
Definition: list.c:495
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
MemoryContext TopTransactionContext
Definition: mcxt.c:154
void pfree(void *pointer)
Definition: mcxt.c:1521
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define NIL
Definition: pg_list.h:68
#define linitial(l)
Definition: pg_list.h:178
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:472
static PyObject * PLy_subtransaction_exit(PyObject *self, PyObject *args)
PyObject * PLy_subtransaction_new(PyObject *self, PyObject *unused)
static PyMethodDef PLy_subtransaction_methods[]
static PyObject * PLy_subtransaction_enter(PyObject *self, PyObject *unused)
static char PLy_subtransaction_doc[]
static PyTypeObject PLy_SubtransactionType
static void PLy_subtransaction_dealloc(PyObject *subxact)
List * explicit_subtransactions
void PLy_subtransaction_init_type(void)
struct PLySubtransactionObject PLySubtransactionObject
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
Definition: pg_list.h:54
PyObject_HEAD bool started
const char * type
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4686
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4788
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4760