Header And Logo

PostgreSQL
| The world's most advanced open source database.

plpy_subxactobject.c

Go to the documentation of this file.
00001 /*
00002  * the PLySubtransaction class
00003  *
00004  * src/pl/plpython/plpy_subxactobject.c
00005  */
00006 
00007 #include "postgres.h"
00008 
00009 #include "access/xact.h"
00010 #include "executor/spi.h"
00011 
00012 #include "plpython.h"
00013 
00014 #include "plpy_subxactobject.h"
00015 
00016 #include "plpy_elog.h"
00017 
00018 
00019 List       *explicit_subtransactions = NIL;
00020 
00021 
00022 static void PLy_subtransaction_dealloc(PyObject *subxact);
00023 static PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
00024 static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
00025 
00026 static char PLy_subtransaction_doc[] = {
00027     "PostgreSQL subtransaction context manager"
00028 };
00029 
00030 static PyMethodDef PLy_subtransaction_methods[] = {
00031     {"__enter__", PLy_subtransaction_enter, METH_VARARGS, NULL},
00032     {"__exit__", PLy_subtransaction_exit, METH_VARARGS, NULL},
00033     /* user-friendly names for Python <2.6 */
00034     {"enter", PLy_subtransaction_enter, METH_VARARGS, NULL},
00035     {"exit", PLy_subtransaction_exit, METH_VARARGS, NULL},
00036     {NULL, NULL, 0, NULL}
00037 };
00038 
00039 static PyTypeObject PLy_SubtransactionType = {
00040     PyVarObject_HEAD_INIT(NULL, 0)
00041     "PLySubtransaction",        /* tp_name */
00042     sizeof(PLySubtransactionObject),    /* tp_size */
00043     0,                          /* tp_itemsize */
00044 
00045     /*
00046      * methods
00047      */
00048     PLy_subtransaction_dealloc, /* tp_dealloc */
00049     0,                          /* tp_print */
00050     0,                          /* tp_getattr */
00051     0,                          /* tp_setattr */
00052     0,                          /* tp_compare */
00053     0,                          /* tp_repr */
00054     0,                          /* tp_as_number */
00055     0,                          /* tp_as_sequence */
00056     0,                          /* tp_as_mapping */
00057     0,                          /* tp_hash */
00058     0,                          /* tp_call */
00059     0,                          /* tp_str */
00060     0,                          /* tp_getattro */
00061     0,                          /* tp_setattro */
00062     0,                          /* tp_as_buffer */
00063     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
00064     PLy_subtransaction_doc,     /* tp_doc */
00065     0,                          /* tp_traverse */
00066     0,                          /* tp_clear */
00067     0,                          /* tp_richcompare */
00068     0,                          /* tp_weaklistoffset */
00069     0,                          /* tp_iter */
00070     0,                          /* tp_iternext */
00071     PLy_subtransaction_methods, /* tp_tpmethods */
00072 };
00073 
00074 
00075 void
00076 PLy_subtransaction_init_type(void)
00077 {
00078     if (PyType_Ready(&PLy_SubtransactionType) < 0)
00079         elog(ERROR, "could not initialize PLy_SubtransactionType");
00080 }
00081 
00082 /* s = plpy.subtransaction() */
00083 PyObject *
00084 PLy_subtransaction_new(PyObject *self, PyObject *unused)
00085 {
00086     PLySubtransactionObject *ob;
00087 
00088     ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
00089 
00090     if (ob == NULL)
00091         return NULL;
00092 
00093     ob->started = false;
00094     ob->exited = false;
00095 
00096     return (PyObject *) ob;
00097 }
00098 
00099 /* Python requires a dealloc function to be defined */
00100 static void
00101 PLy_subtransaction_dealloc(PyObject *subxact)
00102 {
00103 }
00104 
00105 /*
00106  * subxact.__enter__() or subxact.enter()
00107  *
00108  * Start an explicit subtransaction.  SPI calls within an explicit
00109  * subtransaction will not start another one, so you can atomically
00110  * execute many SPI calls and still get a controllable exception if
00111  * one of them fails.
00112  */
00113 static PyObject *
00114 PLy_subtransaction_enter(PyObject *self, PyObject *unused)
00115 {
00116     PLySubtransactionData *subxactdata;
00117     MemoryContext oldcontext;
00118     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
00119 
00120     if (subxact->started)
00121     {
00122         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been entered");
00123         return NULL;
00124     }
00125 
00126     if (subxact->exited)
00127     {
00128         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
00129         return NULL;
00130     }
00131 
00132     subxact->started = true;
00133     oldcontext = CurrentMemoryContext;
00134 
00135     subxactdata = PLy_malloc(sizeof(*subxactdata));
00136     subxactdata->oldcontext = oldcontext;
00137     subxactdata->oldowner = CurrentResourceOwner;
00138 
00139     BeginInternalSubTransaction(NULL);
00140     /* Do not want to leave the previous memory context */
00141     MemoryContextSwitchTo(oldcontext);
00142 
00143     explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
00144 
00145     Py_INCREF(self);
00146     return self;
00147 }
00148 
00149 /*
00150  * subxact.__exit__(exc_type, exc, tb) or subxact.exit(exc_type, exc, tb)
00151  *
00152  * Exit an explicit subtransaction. exc_type is an exception type, exc
00153  * is the exception object, tb is the traceback.  If exc_type is None,
00154  * commit the subtransactiony, if not abort it.
00155  *
00156  * The method signature is chosen to allow subtransaction objects to
00157  * be used as context managers as described in
00158  * <http://www.python.org/dev/peps/pep-0343/>.
00159  */
00160 static PyObject *
00161 PLy_subtransaction_exit(PyObject *self, PyObject *args)
00162 {
00163     PyObject   *type;
00164     PyObject   *value;
00165     PyObject   *traceback;
00166     PLySubtransactionData *subxactdata;
00167     PLySubtransactionObject *subxact = (PLySubtransactionObject *) self;
00168 
00169     if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
00170         return NULL;
00171 
00172     if (!subxact->started)
00173     {
00174         PLy_exception_set(PyExc_ValueError, "this subtransaction has not been entered");
00175         return NULL;
00176     }
00177 
00178     if (subxact->exited)
00179     {
00180         PLy_exception_set(PyExc_ValueError, "this subtransaction has already been exited");
00181         return NULL;
00182     }
00183 
00184     if (explicit_subtransactions == NIL)
00185     {
00186         PLy_exception_set(PyExc_ValueError, "there is no subtransaction to exit from");
00187         return NULL;
00188     }
00189 
00190     subxact->exited = true;
00191 
00192     if (type != Py_None)
00193     {
00194         /* Abort the inner transaction */
00195         RollbackAndReleaseCurrentSubTransaction();
00196     }
00197     else
00198     {
00199         ReleaseCurrentSubTransaction();
00200     }
00201 
00202     subxactdata = (PLySubtransactionData *) linitial(explicit_subtransactions);
00203     explicit_subtransactions = list_delete_first(explicit_subtransactions);
00204 
00205     MemoryContextSwitchTo(subxactdata->oldcontext);
00206     CurrentResourceOwner = subxactdata->oldowner;
00207     PLy_free(subxactdata);
00208 
00209     /*
00210      * AtEOSubXact_SPI() should not have popped any SPI context, but just in
00211      * case it did, make sure we remain connected.
00212      */
00213     SPI_restore_connection();
00214 
00215     Py_INCREF(Py_None);
00216     return Py_None;
00217 }