LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_subxactobject.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 49 56 87.5 %
Date: 2019-11-15 22:06:47 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      19             : List       *explicit_subtransactions = NIL;
      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
      51          46 : PLy_subtransaction_init_type(void)
      52             : {
      53          46 :     if (PyType_Ready(&PLy_SubtransactionType) < 0)
      54           0 :         elog(ERROR, "could not initialize PLy_SubtransactionType");
      55          46 : }
      56             : 
      57             : /* s = plpy.subtransaction() */
      58             : PyObject *
      59          64 : PLy_subtransaction_new(PyObject *self, PyObject *unused)
      60             : {
      61             :     PLySubtransactionObject *ob;
      62             : 
      63          64 :     ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
      64             : 
      65          64 :     if (ob == NULL)
      66           0 :         return NULL;
      67             : 
      68          64 :     ob->started = false;
      69          64 :     ob->exited = false;
      70             : 
      71          64 :     return (PyObject *) ob;
      72             : }
      73             : 
      74             : /* Python requires a dealloc function to be defined */
      75             : static void
      76          62 : PLy_subtransaction_dealloc(PyObject *subxact)
      77             : {
      78          62 : }
      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          64 : PLy_subtransaction_enter(PyObject *self, PyObject *unused)
      90             : {
      91             :     PLySubtransactionData *subxactdata;
      92             :     MemoryContext oldcontext;
      93          64 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
      94             : 
      95          64 :     if (subxact->started)
      96             :     {
      97           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
      98           4 :         return NULL;
      99             :     }
     100             : 
     101          60 :     if (subxact->exited)
     102             :     {
     103           0 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
     104           0 :         return NULL;
     105             :     }
     106             : 
     107          60 :     subxact->started = true;
     108          60 :     oldcontext = CurrentMemoryContext;
     109             : 
     110          60 :     subxactdata = (PLySubtransactionData *)
     111          60 :         MemoryContextAlloc(TopTransactionContext,
     112             :                            sizeof(PLySubtransactionData));
     113             : 
     114          60 :     subxactdata->oldcontext = oldcontext;
     115          60 :     subxactdata->oldowner = CurrentResourceOwner;
     116             : 
     117          60 :     BeginInternalSubTransaction(NULL);
     118             : 
     119             :     /* Be sure that cells of explicit_subtransactions list are long-lived */
     120          60 :     MemoryContextSwitchTo(TopTransactionContext);
     121          60 :     explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
     122             : 
     123             :     /* Caller wants to stay in original memory context */
     124          60 :     MemoryContextSwitchTo(oldcontext);
     125             : 
     126          60 :     Py_INCREF(self);
     127          60 :     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          56 : PLy_subtransaction_exit(PyObject *self, PyObject *args)
     143             : {
     144             :     PyObject   *type;
     145             :     PyObject   *value;
     146             :     PyObject   *traceback;
     147             :     PLySubtransactionData *subxactdata;
     148          56 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
     149             : 
     150          56 :     if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
     151           0 :         return NULL;
     152             : 
     153          56 :     if (!subxact->started)
     154             :     {
     155           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
     156           4 :         return NULL;
     157             :     }
     158             : 
     159          52 :     if (subxact->exited)
     160             :     {
     161           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
     162           4 :         return NULL;
     163             :     }
     164             : 
     165          48 :     if (explicit_subtransactions == NIL)
     166             :     {
     167           0 :         PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
     168           0 :         return NULL;
     169             :     }
     170             : 
     171          48 :     subxact->exited = true;
     172             : 
     173          48 :     if (type != Py_None)
     174             :     {
     175             :         /* Abort the inner transaction */
     176          26 :         RollbackAndReleaseCurrentSubTransaction();
     177             :     }
     178             :     else
     179             :     {
     180          22 :         ReleaseCurrentSubTransaction();
     181             :     }
     182             : 
     183          48 :     subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
     184          48 :     explicit_subtransactions = list_delete_first(explicit_subtransactions);
     185             : 
     186          48 :     MemoryContextSwitchTo(subxactdata->oldcontext);
     187          48 :     CurrentResourceOwner = subxactdata->oldowner;
     188          48 :     pfree(subxactdata);
     189             : 
     190          48 :     Py_RETURN_NONE;
     191             : }

Generated by: LCOV version 1.13