PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
19static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
20
22"PostgreSQL subtransaction context manager";
23
24static PyMethodDef PLy_subtransaction_methods[] = {
25 {"__enter__", PLy_subtransaction_enter, METH_VARARGS, NULL},
26 {"__exit__", PLy_subtransaction_exit, METH_VARARGS, NULL},
27 /* user-friendly names for Python <2.6 */
28 {"enter", PLy_subtransaction_enter, METH_VARARGS, NULL},
29 {"exit", PLy_subtransaction_exit, METH_VARARGS, NULL},
30 {NULL, NULL, 0, NULL}
31};
32
33static PyType_Slot PLySubtransaction_slots[] =
34{
35 {
36 Py_tp_doc, (char *) PLy_subtransaction_doc
37 },
38 {
39 Py_tp_methods, PLy_subtransaction_methods
40 },
41 {
42 0, NULL
43 }
44};
45
46static PyType_Spec PLySubtransaction_spec =
47{
48 .name = "PLySubtransaction",
49 .basicsize = sizeof(PLySubtransactionObject),
50 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
52};
53
54static PyTypeObject *PLy_SubtransactionType;
55
56
57void
59{
60 PLy_SubtransactionType = (PyTypeObject *) PyType_FromSpec(&PLySubtransaction_spec);
62 elog(ERROR, "could not initialize PLy_SubtransactionType");
63}
64
65/* s = plpy.subtransaction() */
66PyObject *
67PLy_subtransaction_new(PyObject *self, PyObject *unused)
68{
70
72 if (ob == NULL)
73 return NULL;
74#if PY_VERSION_HEX < 0x03080000
75 /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
76 Py_INCREF(PLy_SubtransactionType);
77#endif
78
79 ob->started = false;
80 ob->exited = false;
81
82 return (PyObject *) ob;
83}
84
85/*
86 * subxact.__enter__() or subxact.enter()
87 *
88 * Start an explicit subtransaction. SPI calls within an explicit
89 * subtransaction will not start another one, so you can atomically
90 * execute many SPI calls and still get a controllable exception if
91 * one of them fails.
92 */
93static PyObject *
94PLy_subtransaction_enter(PyObject *self, PyObject *unused)
95{
96 PLySubtransactionData *subxactdata;
97 MemoryContext oldcontext;
99
100 if (subxact->started)
101 {
102 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
103 return NULL;
104 }
105
106 if (subxact->exited)
107 {
108 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
109 return NULL;
110 }
111
112 subxact->started = true;
113 oldcontext = CurrentMemoryContext;
114
115 subxactdata = (PLySubtransactionData *)
117 sizeof(PLySubtransactionData));
118
119 subxactdata->oldcontext = oldcontext;
120 subxactdata->oldowner = CurrentResourceOwner;
121
123
124 /* Be sure that cells of explicit_subtransactions list are long-lived */
127
128 /* Caller wants to stay in original memory context */
129 MemoryContextSwitchTo(oldcontext);
130
131 Py_INCREF(self);
132 return self;
133}
134
135/*
136 * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
137 *
138 * Exit an explicit subtransaction. exc_type is an exception type, exc
139 * is the exception object, tb is the traceback. If exc_type is None,
140 * commit the subtransaction, if not abort it.
141 *
142 * The method signature is chosen to allow subtransaction objects to
143 * be used as context managers as described in
144 * <http://www.python.org/dev/peps/pep-0343/>.
145 */
146static PyObject *
147PLy_subtransaction_exit(PyObject *self, PyObject *args)
148{
149 PyObject *type;
150 PyObject *value;
151 PyObject *traceback;
152 PLySubtransactionData *subxactdata;
154
155 if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
156 return NULL;
157
158 if (!subxact->started)
159 {
160 PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
161 return NULL;
162 }
163
164 if (subxact->exited)
165 {
166 PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
167 return NULL;
168 }
169
171 {
172 PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
173 return NULL;
174 }
175
176 subxact->exited = true;
177
178 if (type != Py_None)
179 {
180 /* Abort the inner transaction */
182 }
183 else
184 {
186 }
187
190
191 MemoryContextSwitchTo(subxactdata->oldcontext);
192 CurrentResourceOwner = subxactdata->oldowner;
193 pfree(subxactdata);
194
195 Py_RETURN_NONE;
196}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
static struct @165 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:1260
MemoryContext TopTransactionContext
Definition: mcxt.c:170
void pfree(void *pointer)
Definition: mcxt.c:2150
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
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 PyTypeObject * PLy_SubtransactionType
static PyObject * PLy_subtransaction_enter(PyObject *self, PyObject *unused)
static char PLy_subtransaction_doc[]
static PyType_Spec PLySubtransaction_spec
List * explicit_subtransactions
void PLy_subtransaction_init_type(void)
static PyType_Slot PLySubtransaction_slots[]
struct PLySubtransactionObject PLySubtransactionObject
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
Definition: pg_list.h:54
PyObject_HEAD bool started
const char * type
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4694
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4796
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4768