LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_subxactobject.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 48 55 87.3 %
Date: 2024-03-29 11:11:17 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 "plpy_elog.h"
      11             : #include "plpy_subxactobject.h"
      12             : #include "plpython.h"
      13             : #include "utils/memutils.h"
      14             : 
      15             : List       *explicit_subtransactions = NIL;
      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
      46          46 : PLy_subtransaction_init_type(void)
      47             : {
      48          46 :     if (PyType_Ready(&PLy_SubtransactionType) < 0)
      49           0 :         elog(ERROR, "could not initialize PLy_SubtransactionType");
      50          46 : }
      51             : 
      52             : /* s = plpy.subtransaction() */
      53             : PyObject *
      54          58 : PLy_subtransaction_new(PyObject *self, PyObject *unused)
      55             : {
      56             :     PLySubtransactionObject *ob;
      57             : 
      58          58 :     ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
      59             : 
      60          58 :     if (ob == NULL)
      61           0 :         return NULL;
      62             : 
      63          58 :     ob->started = false;
      64          58 :     ob->exited = false;
      65             : 
      66          58 :     return (PyObject *) ob;
      67             : }
      68             : 
      69             : /* Python requires a dealloc function to be defined */
      70             : static void
      71          58 : PLy_subtransaction_dealloc(PyObject *subxact)
      72             : {
      73          58 : }
      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          58 : PLy_subtransaction_enter(PyObject *self, PyObject *unused)
      85             : {
      86             :     PLySubtransactionData *subxactdata;
      87             :     MemoryContext oldcontext;
      88          58 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
      89             : 
      90          58 :     if (subxact->started)
      91             :     {
      92           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
      93           4 :         return NULL;
      94             :     }
      95             : 
      96          54 :     if (subxact->exited)
      97             :     {
      98           0 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
      99           0 :         return NULL;
     100             :     }
     101             : 
     102          54 :     subxact->started = true;
     103          54 :     oldcontext = CurrentMemoryContext;
     104             : 
     105             :     subxactdata = (PLySubtransactionData *)
     106          54 :         MemoryContextAlloc(TopTransactionContext,
     107             :                            sizeof(PLySubtransactionData));
     108             : 
     109          54 :     subxactdata->oldcontext = oldcontext;
     110          54 :     subxactdata->oldowner = CurrentResourceOwner;
     111             : 
     112          54 :     BeginInternalSubTransaction(NULL);
     113             : 
     114             :     /* Be sure that cells of explicit_subtransactions list are long-lived */
     115          54 :     MemoryContextSwitchTo(TopTransactionContext);
     116          54 :     explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
     117             : 
     118             :     /* Caller wants to stay in original memory context */
     119          54 :     MemoryContextSwitchTo(oldcontext);
     120             : 
     121          54 :     Py_INCREF(self);
     122          54 :     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          50 : PLy_subtransaction_exit(PyObject *self, PyObject *args)
     138             : {
     139             :     PyObject   *type;
     140             :     PyObject   *value;
     141             :     PyObject   *traceback;
     142             :     PLySubtransactionData *subxactdata;
     143          50 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
     144             : 
     145          50 :     if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
     146           0 :         return NULL;
     147             : 
     148          50 :     if (!subxact->started)
     149             :     {
     150           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
     151           4 :         return NULL;
     152             :     }
     153             : 
     154          46 :     if (subxact->exited)
     155             :     {
     156           4 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
     157           4 :         return NULL;
     158             :     }
     159             : 
     160          42 :     if (explicit_subtransactions == NIL)
     161             :     {
     162           0 :         PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
     163           0 :         return NULL;
     164             :     }
     165             : 
     166          42 :     subxact->exited = true;
     167             : 
     168          42 :     if (type != Py_None)
     169             :     {
     170             :         /* Abort the inner transaction */
     171          22 :         RollbackAndReleaseCurrentSubTransaction();
     172             :     }
     173             :     else
     174             :     {
     175          20 :         ReleaseCurrentSubTransaction();
     176             :     }
     177             : 
     178          42 :     subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
     179          42 :     explicit_subtransactions = list_delete_first(explicit_subtransactions);
     180             : 
     181          42 :     MemoryContextSwitchTo(subxactdata->oldcontext);
     182          42 :     CurrentResourceOwner = subxactdata->oldowner;
     183          42 :     pfree(subxactdata);
     184             : 
     185          42 :     Py_RETURN_NONE;
     186             : }

Generated by: LCOV version 1.14