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 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}
32 };
33 
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,
42 };
43 
44 
45 void
47 {
48  if (PyType_Ready(&PLy_SubtransactionType) < 0)
49  elog(ERROR, "could not initialize PLy_SubtransactionType");
50 }
51 
52 /* s = plpy.subtransaction() */
53 PyObject *
54 PLy_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 */
70 static void
71 PLy_subtransaction_dealloc(PyObject *subxact)
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  */
83 static PyObject *
84 PLy_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 */
116  explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
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  */
136 static PyObject *
137 PLy_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 
160  if (explicit_subtransactions == NIL)
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 
178  subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
179  explicit_subtransactions = list_delete_first(explicit_subtransactions);
180 
181  MemoryContextSwitchTo(subxactdata->oldcontext);
182  CurrentResourceOwner = subxactdata->oldowner;
183  pfree(subxactdata);
184 
185  Py_RETURN_NONE;
186 }
#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:4479
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:479
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:4513
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)
static struct @143 value
struct PLySubtransactionObject PLySubtransactionObject
List * lcons(void *datum, List *list)
Definition: list.c:453
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4408
PyObject_HEAD bool started
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:214
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:860
static PyTypeObject PLy_SubtransactionType
static PyMethodDef PLy_subtransaction_methods[]