00001
00002
00003
00004
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
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",
00042 sizeof(PLySubtransactionObject),
00043 0,
00044
00045
00046
00047
00048 PLy_subtransaction_dealloc,
00049 0,
00050 0,
00051 0,
00052 0,
00053 0,
00054 0,
00055 0,
00056 0,
00057 0,
00058 0,
00059 0,
00060 0,
00061 0,
00062 0,
00063 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00064 PLy_subtransaction_doc,
00065 0,
00066 0,
00067 0,
00068 0,
00069 0,
00070 0,
00071 PLy_subtransaction_methods,
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
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
00100 static void
00101 PLy_subtransaction_dealloc(PyObject *subxact)
00102 {
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
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
00141 MemoryContextSwitchTo(oldcontext);
00142
00143 explicit_subtransactions = lcons(subxactdata, explicit_subtransactions);
00144
00145 Py_INCREF(self);
00146 return self;
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
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
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
00211
00212
00213 SPI_restore_connection();
00214
00215 Py_INCREF(Py_None);
00216 return Py_None;
00217 }