LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_subxactobject.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 86.8 % 53 46
Test Date: 2026-07-18 10:15:36 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 65.0 % 20 13

             Branch data     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