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 
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 
26 static PyMethodDef PLy_subtransaction_methods[] = {
27  {"__enter__", PLy_subtransaction_enter, METH_VARARGS, NULL},
28  {"__exit__", PLy_subtransaction_exit, METH_VARARGS, NULL},
29  /* user-friendly names for Python <2.6 */
30  {"enter", PLy_subtransaction_enter, METH_VARARGS, NULL},
31  {"exit", PLy_subtransaction_exit, METH_VARARGS, NULL},
32  {NULL, NULL, 0, NULL}
33 };
34 
35 static PyTypeObject PLy_SubtransactionType = {
36  PyVarObject_HEAD_INIT(NULL, 0)
37  .tp_name = "PLySubtransaction",
38  .tp_basicsize = sizeof(PLySubtransactionObject),
39  .tp_dealloc = PLy_subtransaction_dealloc,
40  .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
41  .tp_doc = PLy_subtransaction_doc,
42  .tp_methods = PLy_subtransaction_methods,
43 };
44 
45 
46 void
48 {
49  if (PyType_Ready(&PLy_SubtransactionType) < 0)
50  elog(ERROR, "could not initialize PLy_SubtransactionType");
51 }
52 
53 /* s = plpy.subtransaction() */
54 PyObject *
55 PLy_subtransaction_new(PyObject *self, PyObject *unused)
56 {
58 
60 
61  if (ob == NULL)
62  return NULL;
63 
64  ob->started = false;
65  ob->exited = false;
66 
67  return (PyObject *) ob;
68 }
69 
70 /* Python requires a dealloc function to be defined */
71 static void
72 PLy_subtransaction_dealloc(PyObject *subxact)
73 {
74 }
75 
76 /*
77  * subxact.__enter__() or subxact.enter()
78  *
79  * Start an explicit subtransaction. SPI calls within an explicit
80  * subtransaction will not start another one, so you can atomically
81  * execute many SPI calls and still get a controllable exception if
82  * one of them fails.
83  */
84 static PyObject *
85 PLy_subtransaction_enter(PyObject *self, PyObject *unused)
86 {
87  PLySubtransactionData *subxactdata;
88  MemoryContext oldcontext;
90 
91  if (subxact->started)
92  {
93  PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
94  return NULL;
95  }
96 
97  if (subxact->exited)
98  {
99  PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
100  return NULL;
101  }
102 
103  subxact->started = true;
104  oldcontext = CurrentMemoryContext;
105 
106  subxactdata = (PLySubtransactionData *)
108  sizeof(PLySubtransactionData));
109 
110  subxactdata->oldcontext = oldcontext;
111  subxactdata->oldowner = CurrentResourceOwner;
112 
114 
115  /* Be sure that cells of explicit_subtransactions list are long-lived */
117  explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
118 
119  /* Caller wants to stay in original memory context */
120  MemoryContextSwitchTo(oldcontext);
121 
122  Py_INCREF(self);
123  return self;
124 }
125 
126 /*
127  * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
128  *
129  * Exit an explicit subtransaction. exc_type is an exception type, exc
130  * is the exception object, tb is the traceback. If exc_type is None,
131  * commit the subtransaction, if not abort it.
132  *
133  * The method signature is chosen to allow subtransaction objects to
134  * be used as context managers as described in
135  * <http://www.python.org/dev/peps/pep-0343/>.
136  */
137 static PyObject *
138 PLy_subtransaction_exit(PyObject *self, PyObject *args)
139 {
140  PyObject *type;
141  PyObject *value;
142  PyObject *traceback;
143  PLySubtransactionData *subxactdata;
145 
146  if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
147  return NULL;
148 
149  if (!subxact->started)
150  {
151  PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
152  return NULL;
153  }
154 
155  if (subxact->exited)
156  {
157  PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
158  return NULL;
159  }
160 
161  if (explicit_subtransactions == NIL)
162  {
163  PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
164  return NULL;
165  }
166 
167  subxact->exited = true;
168 
169  if (type != Py_None)
170  {
171  /* Abort the inner transaction */
173  }
174  else
175  {
177  }
178 
179  subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
180  explicit_subtransactions = list_delete_first(explicit_subtransactions);
181 
182  MemoryContextSwitchTo(subxactdata->oldcontext);
183  CurrentResourceOwner = subxactdata->oldowner;
184  pfree(subxactdata);
185 
186  Py_RETURN_NONE;
187 }
#define NIL
Definition: pg_list.h:65
static char PLy_subtransaction_doc[]
MemoryContext TopTransactionContext
Definition: mcxt.c:49
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4430
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static struct @145 value
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:481
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
void PLy_subtransaction_init_type(void)
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4464
List * explicit_subtransactions
static void PLy_subtransaction_dealloc(PyObject *subxact)
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
static PyObject * PLy_subtransaction_enter(PyObject *self, PyObject *unused)
struct PLySubtransactionObject PLySubtransactionObject
List * lcons(void *datum, List *list)
Definition: list.c:454
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4359
PyObject_HEAD bool started
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:228
static PyObject * PLy_subtransaction_exit(PyObject *self, PyObject *args)
PyObject * PLy_subtransaction_new(PyObject *self, PyObject *unused)
Definition: pg_list.h:50
List * list_delete_first(List *list)
Definition: list.c:861
static PyTypeObject PLy_SubtransactionType
static PyMethodDef PLy_subtransaction_methods[]