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