LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_subxactobject.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 87.3 % 55 48 7 48
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a