#include "utils/memutils.h"
 
 static PyObject *PLy_cursor_query(const char *query);
-static void PLy_cursor_dealloc(PyObject *arg);
+static void PLy_cursor_dealloc(PLyCursorObject *self);
 static PyObject *PLy_cursor_iternext(PyObject *self);
 static PyObject *PLy_cursor_fetch(PyObject *self, PyObject *args);
 static PyObject *PLy_cursor_close(PyObject *self, PyObject *unused);
    {NULL, NULL, 0, NULL}
 };
 
-static PyTypeObject PLy_CursorType = {
-   PyVarObject_HEAD_INIT(NULL, 0)
-   .tp_name = "PLyCursor",
-   .tp_basicsize = sizeof(PLyCursorObject),
-   .tp_dealloc = PLy_cursor_dealloc,
-   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-   .tp_doc = PLy_cursor_doc,
-   .tp_iter = PyObject_SelfIter,
-   .tp_iternext = PLy_cursor_iternext,
-   .tp_methods = PLy_cursor_methods,
+static PyType_Slot PLyCursor_slots[] =
+{
+   {
+       Py_tp_dealloc, PLy_cursor_dealloc
+   },
+   {
+       Py_tp_doc, (char *) PLy_cursor_doc
+   },
+   {
+       Py_tp_iter, PyObject_SelfIter
+   },
+   {
+       Py_tp_iternext, PLy_cursor_iternext
+   },
+   {
+       Py_tp_methods, PLy_cursor_methods
+   },
+   {
+       0, NULL
+   }
 };
 
+static PyType_Spec PLyCursor_spec =
+{
+   .name = "PLyCursor",
+       .basicsize = sizeof(PLyCursorObject),
+       .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .slots = PLyCursor_slots,
+};
+
+static PyTypeObject *PLy_CursorType;
+
 void
 PLy_cursor_init_type(void)
 {
-   if (PyType_Ready(&PLy_CursorType) < 0)
+   PLy_CursorType = (PyTypeObject *) PyType_FromSpec(&PLyCursor_spec);
+   if (!PLy_CursorType)
        elog(ERROR, "could not initialize PLy_CursorType");
 }
 
    volatile MemoryContext oldcontext;
    volatile ResourceOwner oldowner;
 
-   if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
+   if ((cursor = PyObject_New(PLyCursorObject, PLy_CursorType)) == NULL)
        return NULL;
+#if PY_VERSION_HEX < 0x03080000
+   /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
+   Py_INCREF(PLy_CursorType);
+#endif
    cursor->portalname = NULL;
    cursor->closed = false;
    cursor->mcxt = AllocSetContextCreate(TopMemoryContext,
        return NULL;
    }
 
-   if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
+   if ((cursor = PyObject_New(PLyCursorObject, PLy_CursorType)) == NULL)
        return NULL;
+#if PY_VERSION_HEX < 0x03080000
+   /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
+   Py_INCREF(PLy_CursorType);
+#endif
    cursor->portalname = NULL;
    cursor->closed = false;
    cursor->mcxt = AllocSetContextCreate(TopMemoryContext,
 }
 
 static void
-PLy_cursor_dealloc(PyObject *arg)
+PLy_cursor_dealloc(PLyCursorObject *self)
 {
-   PLyCursorObject *cursor;
+#if PY_VERSION_HEX >= 0x03080000
+   PyTypeObject *tp = Py_TYPE(self);
+#endif
    Portal      portal;
 
-   cursor = (PLyCursorObject *) arg;
-
-   if (!cursor->closed)
+   if (!self->closed)
    {
-       portal = GetPortalByName(cursor->portalname);
+       portal = GetPortalByName(self->portalname);
 
        if (PortalIsValid(portal))
        {
            UnpinPortal(portal);
            SPI_cursor_close(portal);
        }
-       cursor->closed = true;
+       self->closed = true;
    }
-   if (cursor->mcxt)
+   if (self->mcxt)
    {
-       MemoryContextDelete(cursor->mcxt);
-       cursor->mcxt = NULL;
+       MemoryContextDelete(self->mcxt);
+       self->mcxt = NULL;
    }
-   arg->ob_type->tp_free(arg);
+
+   PyObject_Free(self);
+#if PY_VERSION_HEX >= 0x03080000
+   /* This was not needed before Python 3.8 (Python issue 35810) */
+   Py_DECREF(tp);
+#endif
 }
 
 static PyObject *
 
 #include "plpython.h"
 #include "utils/memutils.h"
 
-static void PLy_plan_dealloc(PyObject *arg);
+static void PLy_plan_dealloc(PLyPlanObject *self);
 static PyObject *PLy_plan_cursor(PyObject *self, PyObject *args);
 static PyObject *PLy_plan_execute(PyObject *self, PyObject *args);
 static PyObject *PLy_plan_status(PyObject *self, PyObject *args);
    {NULL, NULL, 0, NULL}
 };
 
-static PyTypeObject PLy_PlanType = {
-   PyVarObject_HEAD_INIT(NULL, 0)
-   .tp_name = "PLyPlan",
-   .tp_basicsize = sizeof(PLyPlanObject),
-   .tp_dealloc = PLy_plan_dealloc,
-   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-   .tp_doc = PLy_plan_doc,
-   .tp_methods = PLy_plan_methods,
+static PyType_Slot PLyPlan_slots[] =
+{
+   {
+       Py_tp_dealloc, PLy_plan_dealloc
+   },
+   {
+       Py_tp_doc, (char *) PLy_plan_doc
+   },
+   {
+       Py_tp_methods, PLy_plan_methods
+   },
+   {
+       0, NULL
+   }
 };
 
+static PyType_Spec PLyPlan_spec =
+{
+   .name = "PLyPlan",
+       .basicsize = sizeof(PLyPlanObject),
+       .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .slots = PLyPlan_slots,
+};
+
+static PyTypeObject *PLy_PlanType;
+
 void
 PLy_plan_init_type(void)
 {
-   if (PyType_Ready(&PLy_PlanType) < 0)
+   PLy_PlanType = (PyTypeObject *) PyType_FromSpec(&PLyPlan_spec);
+   if (!PLy_PlanType)
        elog(ERROR, "could not initialize PLy_PlanType");
 }
 
 {
    PLyPlanObject *ob;
 
-   if ((ob = PyObject_New(PLyPlanObject, &PLy_PlanType)) == NULL)
+   if ((ob = PyObject_New(PLyPlanObject, PLy_PlanType)) == NULL)
        return NULL;
+#if PY_VERSION_HEX < 0x03080000
+   /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
+   Py_INCREF(PLy_PlanType);
+#endif
 
    ob->plan = NULL;
    ob->nargs = 0;
 bool
 is_PLyPlanObject(PyObject *ob)
 {
-   return ob->ob_type == &PLy_PlanType;
+   return ob->ob_type == PLy_PlanType;
 }
 
 static void
-PLy_plan_dealloc(PyObject *arg)
+PLy_plan_dealloc(PLyPlanObject *self)
 {
-   PLyPlanObject *ob = (PLyPlanObject *) arg;
+#if PY_VERSION_HEX >= 0x03080000
+   PyTypeObject *tp = Py_TYPE(self);
+#endif
 
-   if (ob->plan)
+   if (self->plan)
    {
-       SPI_freeplan(ob->plan);
-       ob->plan = NULL;
+       SPI_freeplan(self->plan);
+       self->plan = NULL;
    }
-   if (ob->mcxt)
+   if (self->mcxt)
    {
-       MemoryContextDelete(ob->mcxt);
-       ob->mcxt = NULL;
+       MemoryContextDelete(self->mcxt);
+       self->mcxt = NULL;
    }
-   arg->ob_type->tp_free(arg);
+
+   PyObject_Free(self);
+#if PY_VERSION_HEX >= 0x03080000
+   /* This was not needed before Python 3.8 (Python issue 35810) */
+   Py_DECREF(tp);
+#endif
 }
 
 
 
 {
    PyObject   *crv = NULL;
    char       *msrc;
+   PyObject   *code0;
 
    proc->globals = PyDict_Copy(PLy_interp_globals);
 
    msrc = PLy_procedure_munge_source(proc->pyname, src);
    /* Save the mangled source for later inclusion in tracebacks */
    proc->src = MemoryContextStrdup(proc->mcxt, msrc);
-   crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
+   code0 = Py_CompileString(msrc, "<string>", Py_file_input);
+   if (code0)
+       crv = PyEval_EvalCode(code0, proc->globals, NULL);
    pfree(msrc);
 
    if (crv != NULL)
 
 #include "plpy_resultobject.h"
 #include "plpython.h"
 
-static void PLy_result_dealloc(PyObject *arg);
+static void PLy_result_dealloc(PLyResultObject *self);
 static PyObject *PLy_result_colnames(PyObject *self, PyObject *unused);
 static PyObject *PLy_result_coltypes(PyObject *self, PyObject *unused);
 static PyObject *PLy_result_coltypmods(PyObject *self, PyObject *unused);
 
 static char PLy_result_doc[] = "Results of a PostgreSQL query";
 
-static PySequenceMethods PLy_result_as_sequence = {
-   .sq_length = PLy_result_length,
-   .sq_item = PLy_result_item,
-};
-
-static PyMappingMethods PLy_result_as_mapping = {
-   .mp_length = PLy_result_length,
-   .mp_subscript = PLy_result_subscript,
-   .mp_ass_subscript = PLy_result_ass_subscript,
-};
-
 static PyMethodDef PLy_result_methods[] = {
    {"colnames", PLy_result_colnames, METH_NOARGS, NULL},
    {"coltypes", PLy_result_coltypes, METH_NOARGS, NULL},
    {NULL, NULL, 0, NULL}
 };
 
-static PyTypeObject PLy_ResultType = {
-   PyVarObject_HEAD_INIT(NULL, 0)
-   .tp_name = "PLyResult",
-   .tp_basicsize = sizeof(PLyResultObject),
-   .tp_dealloc = PLy_result_dealloc,
-   .tp_as_sequence = &PLy_result_as_sequence,
-   .tp_as_mapping = &PLy_result_as_mapping,
-   .tp_str = &PLy_result_str,
-   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-   .tp_doc = PLy_result_doc,
-   .tp_methods = PLy_result_methods,
+static PyType_Slot PLyResult_slots[] =
+{
+   {
+       Py_tp_dealloc, PLy_result_dealloc
+   },
+   {
+       Py_sq_length, PLy_result_length
+   },
+   {
+       Py_sq_item, PLy_result_item
+   },
+   {
+       Py_mp_length, PLy_result_length
+   },
+   {
+       Py_mp_subscript, PLy_result_subscript
+   },
+   {
+       Py_mp_ass_subscript, PLy_result_ass_subscript
+   },
+   {
+       Py_tp_str, PLy_result_str
+   },
+   {
+       Py_tp_doc, (char *) PLy_result_doc
+   },
+   {
+       Py_tp_methods, PLy_result_methods
+   },
+   {
+       0, NULL
+   }
+};
+
+static PyType_Spec PLyResult_spec =
+{
+   .name = "PLyResult",
+       .basicsize = sizeof(PLyResultObject),
+       .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .slots = PLyResult_slots,
 };
 
+static PyTypeObject *PLy_ResultType;
+
 void
 PLy_result_init_type(void)
 {
-   if (PyType_Ready(&PLy_ResultType) < 0)
+   PLy_ResultType = (PyTypeObject *) PyType_FromSpec(&PLyResult_spec);
+   if (!PLy_ResultType)
        elog(ERROR, "could not initialize PLy_ResultType");
 }
 
 {
    PLyResultObject *ob;
 
-   if ((ob = PyObject_New(PLyResultObject, &PLy_ResultType)) == NULL)
+   if ((ob = PyObject_New(PLyResultObject, PLy_ResultType)) == NULL)
        return NULL;
+#if PY_VERSION_HEX < 0x03080000
+   /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
+   Py_INCREF(PLy_ResultType);
+#endif
 
    /* ob->tuples = NULL; */
 
 }
 
 static void
-PLy_result_dealloc(PyObject *arg)
+PLy_result_dealloc(PLyResultObject *self)
 {
-   PLyResultObject *ob = (PLyResultObject *) arg;
-
-   Py_XDECREF(ob->nrows);
-   Py_XDECREF(ob->rows);
-   Py_XDECREF(ob->status);
-   if (ob->tupdesc)
+#if PY_VERSION_HEX >= 0x03080000
+   PyTypeObject *tp = Py_TYPE(self);
+#endif
+
+   Py_XDECREF(self->nrows);
+   Py_XDECREF(self->rows);
+   Py_XDECREF(self->status);
+   if (self->tupdesc)
    {
-       FreeTupleDesc(ob->tupdesc);
-       ob->tupdesc = NULL;
+       FreeTupleDesc(self->tupdesc);
+       self->tupdesc = NULL;
    }
 
-   arg->ob_type->tp_free(arg);
+   PyObject_Free(self);
+#if PY_VERSION_HEX >= 0x03080000
+   /* This was not needed before Python 3.8 (Python issue 35810) */
+   Py_DECREF(tp);
+#endif
 }
 
 static PyObject *
    {
        Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-       PyList_SET_ITEM(list, i, PLyUnicode_FromString(NameStr(attr->attname)));
+       PyList_SetItem(list, i, PLyUnicode_FromString(NameStr(attr->attname)));
    }
 
    return list;
    {
        Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-       PyList_SET_ITEM(list, i, PyLong_FromLong(attr->atttypid));
+       PyList_SetItem(list, i, PyLong_FromLong(attr->atttypid));
    }
 
    return list;
    {
        Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-       PyList_SET_ITEM(list, i, PyLong_FromLong(attr->atttypmod));
+       PyList_SetItem(list, i, PyLong_FromLong(attr->atttypmod));
    }
 
    return list;
    PLyResultObject *ob = (PLyResultObject *) arg;
 
    return PyUnicode_FromFormat("<%s status=%S nrows=%S rows=%S>",
-                               Py_TYPE(ob)->tp_name,
+                               "PLyResult",
                                ob->status,
                                ob->nrows,
                                ob->rows);
 
 List      *explicit_subtransactions = NIL;
 
 
-static void PLy_subtransaction_dealloc(PyObject *subxact);
 static PyObject *PLy_subtransaction_enter(PyObject *self, PyObject *unused);
 static PyObject *PLy_subtransaction_exit(PyObject *self, PyObject *args);
 
    {NULL, NULL, 0, NULL}
 };
 
-static PyTypeObject PLy_SubtransactionType = {
-   PyVarObject_HEAD_INIT(NULL, 0)
-   .tp_name = "PLySubtransaction",
-   .tp_basicsize = sizeof(PLySubtransactionObject),
-   .tp_dealloc = PLy_subtransaction_dealloc,
-   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-   .tp_doc = PLy_subtransaction_doc,
-   .tp_methods = PLy_subtransaction_methods,
+static PyType_Slot PLySubtransaction_slots[] =
+{
+   {
+       Py_tp_doc, (char *) PLy_subtransaction_doc
+   },
+   {
+       Py_tp_methods, PLy_subtransaction_methods
+   },
+   {
+       0, NULL
+   }
 };
 
+static PyType_Spec PLySubtransaction_spec =
+{
+   .name = "PLySubtransaction",
+       .basicsize = sizeof(PLySubtransactionObject),
+       .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .slots = PLySubtransaction_slots,
+};
+
+static PyTypeObject *PLy_SubtransactionType;
+
 
 void
 PLy_subtransaction_init_type(void)
 {
-   if (PyType_Ready(&PLy_SubtransactionType) < 0)
+   PLy_SubtransactionType = (PyTypeObject *) PyType_FromSpec(&PLySubtransaction_spec);
+   if (!PLy_SubtransactionType)
        elog(ERROR, "could not initialize PLy_SubtransactionType");
 }
 
 {
    PLySubtransactionObject *ob;
 
-   ob = PyObject_New(PLySubtransactionObject, &PLy_SubtransactionType);
-
+   ob = PyObject_New(PLySubtransactionObject, PLy_SubtransactionType);
    if (ob == NULL)
        return NULL;
+#if PY_VERSION_HEX < 0x03080000
+   /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
+   Py_INCREF(PLy_SubtransactionType);
+#endif
 
    ob->started = false;
    ob->exited = false;
    return (PyObject *) ob;
 }
 
-/* Python requires a dealloc function to be defined */
-static void
-PLy_subtransaction_dealloc(PyObject *subxact)
-{
-}
-
 /*
  * subxact.__enter__() or subxact.enter()
  *
 
 
            sublist = PLyList_FromArray_recurse(elm, dims, ndim, dim + 1,
                                                dataptr_p, bitmap_p, bitmask_p);
-           PyList_SET_ITEM(list, i, sublist);
+           PyList_SetItem(list, i, sublist);
        }
    }
    else
            if (bitmap && (*bitmap & bitmask) == 0)
            {
                Py_INCREF(Py_None);
-               PyList_SET_ITEM(list, i, Py_None);
+               PyList_SetItem(list, i, Py_None);
            }
            else
            {
                Datum       itemvalue;
 
                itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
-               PyList_SET_ITEM(list, i, elm->func(elm, itemvalue));
+               PyList_SetItem(list, i, elm->func(elm, itemvalue));
                dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
                dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
            }