bpo-41861: Convert _sqlite3 RowType and StatementType to heap types (GH-22444)

diff --git a/Modules/_sqlite/cache.c b/Modules/_sqlite/cache.c
index c417ce8..0b02be4 100644
--- a/Modules/_sqlite/cache.c
+++ b/Modules/_sqlite/cache.c
@@ -267,7 +267,7 @@
 static PyType_Spec pysqlite_NodeType_spec = {
     .name = MODULE_NAME ".Node",
     .basicsize = sizeof(pysqlite_Node),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE,
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     .slots = pysqlite_NodeType_slots,
 };
 PyTypeObject *pysqlite_NodeType = NULL;
@@ -291,7 +291,7 @@
 static PyType_Spec pysqlite_CacheType_spec = {
     .name = MODULE_NAME ".Cache",
     .basicsize = sizeof(pysqlite_Cache),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE,
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     .slots = pysqlite_CacheType_slots,
 };
 PyTypeObject *pysqlite_CacheType = NULL;
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 121850a..91e9046 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -1234,7 +1234,7 @@
 
     _pysqlite_drop_unused_statement_references(self);
 
-    statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
+    statement = PyObject_New(pysqlite_Statement, pysqlite_StatementType);
     if (!statement) {
         return NULL;
     }
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 5cfb4b9..dbbdb12 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -472,7 +472,7 @@
 
     if (self->statement->in_use) {
         Py_SETREF(self->statement,
-                  PyObject_New(pysqlite_Statement, &pysqlite_StatementType));
+                  PyObject_New(pysqlite_Statement, pysqlite_StatementType));
         if (!self->statement) {
             goto error;
         }
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index d0a546c..8ac9ea8 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -352,11 +352,11 @@
     module = PyModule_Create(&_sqlite3module);
 
     if (!module ||
-        (pysqlite_row_setup_types() < 0) ||
+        (pysqlite_row_setup_types(module) < 0) ||
         (pysqlite_cursor_setup_types() < 0) ||
         (pysqlite_connection_setup_types() < 0) ||
         (pysqlite_cache_setup_types(module) < 0) ||
-        (pysqlite_statement_setup_types() < 0) ||
+        (pysqlite_statement_setup_types(module) < 0) ||
         (pysqlite_prepare_protocol_setup_types(module) < 0)
        ) {
         Py_XDECREF(module);
@@ -366,7 +366,7 @@
     ADD_TYPE(module, pysqlite_ConnectionType);
     ADD_TYPE(module, pysqlite_CursorType);
     ADD_TYPE(module, *pysqlite_PrepareProtocolType);
-    ADD_TYPE(module, pysqlite_RowType);
+    ADD_TYPE(module, *pysqlite_RowType);
 
     if (!(dict = PyModule_GetDict(module))) {
         goto error;
diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c
index 7daf8a6..089d66b 100644
--- a/Modules/_sqlite/prepare_protocol.c
+++ b/Modules/_sqlite/prepare_protocol.c
@@ -46,7 +46,7 @@
 static PyType_Spec type_spec = {
     .name = MODULE_NAME ".PrepareProtocol",
     .basicsize = sizeof(pysqlite_PrepareProtocol),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE,
+    .flags = Py_TPFLAGS_DEFAULT,
     .slots = type_slots,
 };
 
diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c
index 4b47108..85179e7 100644
--- a/Modules/_sqlite/row.c
+++ b/Modules/_sqlite/row.c
@@ -26,10 +26,13 @@
 
 void pysqlite_row_dealloc(pysqlite_Row* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     Py_XDECREF(self->data);
     Py_XDECREF(self->description);
 
-    Py_TYPE(self)->tp_free((PyObject*)self);
+    tp->tp_free(self);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -192,7 +195,7 @@
     if (opid != Py_EQ && opid != Py_NE)
         Py_RETURN_NOTIMPLEMENTED;
 
-    if (PyObject_TypeCheck(_other, &pysqlite_RowType)) {
+    if (PyObject_TypeCheck(_other, pysqlite_RowType)) {
         pysqlite_Row *other = (pysqlite_Row *)_other;
         int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
         if (eq < 0) {
@@ -206,73 +209,40 @@
     Py_RETURN_NOTIMPLEMENTED;
 }
 
-PyMappingMethods pysqlite_row_as_mapping = {
-    /* mp_length        */ (lenfunc)pysqlite_row_length,
-    /* mp_subscript     */ (binaryfunc)pysqlite_row_subscript,
-    /* mp_ass_subscript */ (objobjargproc)0,
-};
-
-static PySequenceMethods pysqlite_row_as_sequence = {
-   /* sq_length */         (lenfunc)pysqlite_row_length,
-   /* sq_concat */         0,
-   /* sq_repeat */         0,
-   /* sq_item */           (ssizeargfunc)pysqlite_row_item,
-};
-
-
-static PyMethodDef pysqlite_row_methods[] = {
+static PyMethodDef row_methods[] = {
     {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
         PyDoc_STR("Returns the keys of the row.")},
     {NULL, NULL}
 };
 
-
-PyTypeObject pysqlite_RowType = {
-        PyVarObject_HEAD_INIT(NULL, 0)
-        MODULE_NAME ".Row",                             /* tp_name */
-        sizeof(pysqlite_Row),                           /* tp_basicsize */
-        0,                                              /* tp_itemsize */
-        (destructor)pysqlite_row_dealloc,               /* tp_dealloc */
-        0,                                              /* tp_vectorcall_offset */
-        0,                                              /* tp_getattr */
-        0,                                              /* tp_setattr */
-        0,                                              /* tp_as_async */
-        0,                                              /* tp_repr */
-        0,                                              /* tp_as_number */
-        0,                                              /* tp_as_sequence */
-        0,                                              /* tp_as_mapping */
-        (hashfunc)pysqlite_row_hash,                    /* tp_hash */
-        0,                                              /* tp_call */
-        0,                                              /* tp_str */
-        0,                                              /* tp_getattro */
-        0,                                              /* tp_setattro */
-        0,                                              /* tp_as_buffer */
-        Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,         /* tp_flags */
-        0,                                              /* tp_doc */
-        (traverseproc)0,                                /* tp_traverse */
-        0,                                              /* tp_clear */
-        (richcmpfunc)pysqlite_row_richcompare,          /* tp_richcompare */
-        0,                                              /* tp_weaklistoffset */
-        (getiterfunc)pysqlite_iter,                     /* tp_iter */
-        0,                                              /* tp_iternext */
-        pysqlite_row_methods,                           /* tp_methods */
-        0,                                              /* tp_members */
-        0,                                              /* tp_getset */
-        0,                                              /* tp_base */
-        0,                                              /* tp_dict */
-        0,                                              /* tp_descr_get */
-        0,                                              /* tp_descr_set */
-        0,                                              /* tp_dictoffset */
-        0,                                              /* tp_init */
-        0,                                              /* tp_alloc */
-        0,                                              /* tp_new */
-        0                                               /* tp_free */
+static PyType_Slot row_slots[] = {
+    {Py_tp_dealloc, pysqlite_row_dealloc},
+    {Py_tp_hash, pysqlite_row_hash},
+    {Py_tp_methods, row_methods},
+    {Py_tp_richcompare, pysqlite_row_richcompare},
+    {Py_tp_iter, pysqlite_iter},
+    {Py_mp_length, pysqlite_row_length},
+    {Py_mp_subscript, pysqlite_row_subscript},
+    {Py_sq_length, pysqlite_row_length},
+    {Py_sq_item, pysqlite_row_item},
+    {Py_tp_new, pysqlite_row_new},
+    {0, NULL},
 };
 
-extern int pysqlite_row_setup_types(void)
+static PyType_Spec row_spec = {
+    .name = MODULE_NAME ".Row",
+    .basicsize = sizeof(pysqlite_Row),
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    .slots = row_slots,
+};
+
+PyTypeObject *pysqlite_RowType = NULL;
+
+extern int pysqlite_row_setup_types(PyObject *module)
 {
-    pysqlite_RowType.tp_new = pysqlite_row_new;
-    pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping;
-    pysqlite_RowType.tp_as_sequence = &pysqlite_row_as_sequence;
-    return PyType_Ready(&pysqlite_RowType);
+    pysqlite_RowType = (PyTypeObject *)PyType_FromModuleAndSpec(module, &row_spec, NULL);
+    if (pysqlite_RowType == NULL) {
+        return -1;
+    }
+    return 0;
 }
diff --git a/Modules/_sqlite/row.h b/Modules/_sqlite/row.h
index 4ad506f..2dac41e 100644
--- a/Modules/_sqlite/row.h
+++ b/Modules/_sqlite/row.h
@@ -33,8 +33,8 @@
     PyObject* description;
 } pysqlite_Row;
 
-extern PyTypeObject pysqlite_RowType;
+extern PyTypeObject *pysqlite_RowType;
 
-int pysqlite_row_setup_types(void);
+int pysqlite_row_setup_types(PyObject *module);
 
 #endif
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index 0458e11..4682d28 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -371,6 +371,8 @@
 
 void pysqlite_statement_dealloc(pysqlite_Statement* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     if (self->st) {
         Py_BEGIN_ALLOW_THREADS
         sqlite3_finalize(self->st);
@@ -385,7 +387,8 @@
         PyObject_ClearWeakRefs((PyObject*)self);
     }
 
-    Py_TYPE(self)->tp_free((PyObject*)self);
+    tp->tp_free(self);
+    Py_DECREF(tp);
 }
 
 /*
@@ -458,50 +461,30 @@
     return 0;
 }
 
-PyTypeObject pysqlite_StatementType = {
-        PyVarObject_HEAD_INIT(NULL, 0)
-        MODULE_NAME ".Statement",                       /* tp_name */
-        sizeof(pysqlite_Statement),                     /* tp_basicsize */
-        0,                                              /* tp_itemsize */
-        (destructor)pysqlite_statement_dealloc,         /* tp_dealloc */
-        0,                                              /* tp_vectorcall_offset */
-        0,                                              /* tp_getattr */
-        0,                                              /* tp_setattr */
-        0,                                              /* tp_as_async */
-        0,                                              /* tp_repr */
-        0,                                              /* tp_as_number */
-        0,                                              /* tp_as_sequence */
-        0,                                              /* tp_as_mapping */
-        0,                                              /* tp_hash */
-        0,                                              /* tp_call */
-        0,                                              /* tp_str */
-        0,                                              /* tp_getattro */
-        0,                                              /* tp_setattro */
-        0,                                              /* tp_as_buffer */
-        Py_TPFLAGS_DEFAULT,                             /* tp_flags */
-        0,                                              /* tp_doc */
-        0,                                              /* tp_traverse */
-        0,                                              /* tp_clear */
-        0,                                              /* tp_richcompare */
-        offsetof(pysqlite_Statement, in_weakreflist),   /* tp_weaklistoffset */
-        0,                                              /* tp_iter */
-        0,                                              /* tp_iternext */
-        0,                                              /* tp_methods */
-        0,                                              /* tp_members */
-        0,                                              /* tp_getset */
-        0,                                              /* tp_base */
-        0,                                              /* tp_dict */
-        0,                                              /* tp_descr_get */
-        0,                                              /* tp_descr_set */
-        0,                                              /* tp_dictoffset */
-        (initproc)0,                                    /* tp_init */
-        0,                                              /* tp_alloc */
-        0,                                              /* tp_new */
-        0                                               /* tp_free */
+static PyMemberDef stmt_members[] = {
+    {"__weaklistoffset__", T_PYSSIZET, offsetof(pysqlite_Statement, in_weakreflist), READONLY},
+    {NULL},
+};
+static PyType_Slot stmt_slots[] = {
+    {Py_tp_members, stmt_members},
+    {Py_tp_dealloc, pysqlite_statement_dealloc},
+    {Py_tp_new, PyType_GenericNew},
+    {0, NULL},
 };
 
-extern int pysqlite_statement_setup_types(void)
+static PyType_Spec stmt_spec = {
+    .name = MODULE_NAME ".Statement",
+    .basicsize = sizeof(pysqlite_Statement),
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = stmt_slots,
+};
+PyTypeObject *pysqlite_StatementType = NULL;
+
+extern int pysqlite_statement_setup_types(PyObject *module)
 {
-    pysqlite_StatementType.tp_new = PyType_GenericNew;
-    return PyType_Ready(&pysqlite_StatementType);
+    pysqlite_StatementType = (PyTypeObject *)PyType_FromModuleAndSpec(module, &stmt_spec, NULL);
+    if (pysqlite_StatementType == NULL) {
+        return -1;
+    }
+    return 0;
 }
diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h
index 5002f02..b426036 100644
--- a/Modules/_sqlite/statement.h
+++ b/Modules/_sqlite/statement.h
@@ -43,7 +43,7 @@
     PyObject* in_weakreflist; /* List of weak references */
 } pysqlite_Statement;
 
-extern PyTypeObject pysqlite_StatementType;
+extern PyTypeObject *pysqlite_StatementType;
 
 int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql);
 void pysqlite_statement_dealloc(pysqlite_Statement* self);
@@ -55,6 +55,6 @@
 int pysqlite_statement_reset(pysqlite_Statement* self);
 void pysqlite_statement_mark_dirty(pysqlite_Statement* self);
 
-int pysqlite_statement_setup_types(void);
+int pysqlite_statement_setup_types(PyObject *module);
 
 #endif