LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_subxactobject.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 86.8 % 53 46
Test Date: 2026-03-14 12:15:02 Functions: 100.0 % 4 4
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 "plpy_util.h"
      13              : #include "utils/memutils.h"
      14              : 
      15              : List       *explicit_subtransactions = NIL;
      16              : 
      17              : 
      18              : static PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
      19              : static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
      20              : 
      21              : static char PLy_subtransaction_doc[] =
      22              : "PostgreSQL subtransaction context manager";
      23              : 
      24              : static PyMethodDef PLy_subtransaction_methods[] = {
      25              :     {"__enter__", PLy_subtransaction_enter, METH_VARARGS, NULL},
      26              :     {"__exit__", PLy_subtransaction_exit, METH_VARARGS, NULL},
      27              :     /* user-friendly names for Python <2.6 */
      28              :     {"enter", PLy_subtransaction_enter, METH_VARARGS, NULL},
      29              :     {"exit", PLy_subtransaction_exit, METH_VARARGS, NULL},
      30              :     {NULL, NULL, 0, NULL}
      31              : };
      32              : 
      33              : static PyType_Slot PLySubtransaction_slots[] =
      34              : {
      35              :     {
      36              :         Py_tp_doc, (char *) PLy_subtransaction_doc
      37              :     },
      38              :     {
      39              :         Py_tp_methods, PLy_subtransaction_methods
      40              :     },
      41              :     {
      42              :         0, NULL
      43              :     }
      44              : };
      45              : 
      46              : static PyType_Spec PLySubtransaction_spec =
      47              : {
      48              :     .name = "PLySubtransaction",
      49              :     .basicsize = sizeof(PLySubtransactionObject),
      50              :     .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
      51              :     .slots = PLySubtransaction_slots,
      52              : };
      53              : 
      54              : static PyTypeObject *PLy_SubtransactionType;
      55              : 
      56              : 
      57              : void
      58           23 : PLy_subtransaction_init_type(void)
      59              : {
      60           23 :     PLy_SubtransactionType = (PyTypeObject *) PyType_FromSpec(&PLySubtransaction_spec);
      61           23 :     if (!PLy_SubtransactionType)
      62            0 :         elog(ERROR, "could not initialize PLy_SubtransactionType");
      63           23 : }
      64              : 
      65              : /* s = plpy.subtransaction() */
      66              : PyObject *
      67           29 : PLy_subtransaction_new(PyObject *self, PyObject *unused)
      68              : {
      69              :     PLySubtransactionObject *ob;
      70              : 
      71           29 :     ob = PyObject_New(PLySubtransactionObject, PLy_SubtransactionType);
      72           29 :     if (ob == NULL)
      73            0 :         return NULL;
      74              : #if PY_VERSION_HEX < 0x03080000
      75              :     /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
      76              :     Py_INCREF(PLy_SubtransactionType);
      77              : #endif
      78              : 
      79           29 :     ob->started = false;
      80           29 :     ob->exited = false;
      81              : 
      82           29 :     return (PyObject *) ob;
      83              : }
      84              : 
      85              : /*
      86              :  * subxact.__enter__() or subxact.enter()
      87              :  *
      88              :  * Start an explicit subtransaction.  SPI calls within an explicit
      89              :  * subtransaction will not start another one, so you can atomically
      90              :  * execute many SPI calls and still get a controllable exception if
      91              :  * one of them fails.
      92              :  */
      93              : static PyObject *
      94           29 : PLy_subtransaction_enter(PyObject *self, PyObject *unused)
      95              : {
      96              :     PLySubtransactionData *subxactdata;
      97              :     MemoryContext oldcontext;
      98           29 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
      99              : 
     100           29 :     if (subxact->started)
     101              :     {
     102            2 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
     103            2 :         return NULL;
     104              :     }
     105              : 
     106           27 :     if (subxact->exited)
     107              :     {
     108            0 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
     109            0 :         return NULL;
     110              :     }
     111              : 
     112           27 :     subxact->started = true;
     113           27 :     oldcontext = CurrentMemoryContext;
     114              : 
     115              :     subxactdata = (PLySubtransactionData *)
     116           27 :         MemoryContextAlloc(TopTransactionContext,
     117              :                            sizeof(PLySubtransactionData));
     118              : 
     119           27 :     subxactdata->oldcontext = oldcontext;
     120           27 :     subxactdata->oldowner = CurrentResourceOwner;
     121              : 
     122           27 :     BeginInternalSubTransaction(NULL);
     123              : 
     124              :     /* Be sure that cells of explicit_subtransactions list are long-lived */
     125           27 :     MemoryContextSwitchTo(TopTransactionContext);
     126           27 :     explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
     127              : 
     128              :     /* Caller wants to stay in original memory context */
     129           27 :     MemoryContextSwitchTo(oldcontext);
     130              : 
     131              :     Py_INCREF(self);
     132           27 :     return self;
     133              : }
     134              : 
     135              : /*
     136              :  * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
     137              :  *
     138              :  * Exit an explicit subtransaction. exc_type is an exception type, exc
     139              :  * is the exception object, tb is the traceback.  If exc_type is None,
     140              :  * commit the subtransaction, if not abort it.
     141              :  *
     142              :  * The method signature is chosen to allow subtransaction objects to
     143              :  * be used as context managers as described in
     144              :  * <http://www.python.org/dev/peps/pep-0343/>.
     145              :  */
     146              : static PyObject *
     147           25 : PLy_subtransaction_exit(PyObject *self, PyObject *args)
     148              : {
     149              :     PyObject   *type;
     150              :     PyObject   *value;
     151              :     PyObject   *traceback;
     152              :     PLySubtransactionData *subxactdata;
     153           25 :     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
     154              : 
     155           25 :     if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
     156            0 :         return NULL;
     157              : 
     158           25 :     if (!subxact->started)
     159              :     {
     160            2 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
     161            2 :         return NULL;
     162              :     }
     163              : 
     164           23 :     if (subxact->exited)
     165              :     {
     166            2 :         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
     167            2 :         return NULL;
     168              :     }
     169              : 
     170           21 :     if (explicit_subtransactions == NIL)
     171              :     {
     172            0 :         PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
     173            0 :         return NULL;
     174              :     }
     175              : 
     176           21 :     subxact->exited = true;
     177              : 
     178           21 :     if (type != Py_None)
     179              :     {
     180              :         /* Abort the inner transaction */
     181           11 :         RollbackAndReleaseCurrentSubTransaction();
     182              :     }
     183              :     else
     184              :     {
     185           10 :         ReleaseCurrentSubTransaction();
     186              :     }
     187              : 
     188           21 :     subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
     189           21 :     explicit_subtransactions = list_delete_first(explicit_subtransactions);
     190              : 
     191           21 :     MemoryContextSwitchTo(subxactdata->oldcontext);
     192           21 :     CurrentResourceOwner = subxactdata->oldowner;
     193           21 :     pfree(subxactdata);
     194              : 
     195           21 :     Py_RETURN_NONE;
     196              : }
        

Generated by: LCOV version 2.0-1