From 0227fb1a996315c61bda26aa905d5b1ed30da8bd Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 6 Mar 2022 16:57:28 -0800
Subject: [PATCH v7 3/4] plpython: Code cleanup related to removal of Python 2
 support.

Reviewed-By: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://postgr.es/m/20211031184548.g4sxfe47n2kyi55r@alap3.anarazel.de
---
 src/pl/plpython/plpy_cursorobject.c       |  8 +--
 src/pl/plpython/plpy_elog.c               | 26 +++++-----
 src/pl/plpython/plpy_exec.c               | 44 ++++++++---------
 src/pl/plpython/plpy_main.c               | 59 ++++-------------------
 src/pl/plpython/plpy_planobject.c         |  2 +-
 src/pl/plpython/plpy_plpymodule.c         | 32 +++---------
 src/pl/plpython/plpy_plpymodule.h         |  2 -
 src/pl/plpython/plpy_resultobject.c       | 16 ++----
 src/pl/plpython/plpy_spi.c                | 10 ++--
 src/pl/plpython/plpy_typeio.c             | 28 ++++-------
 src/pl/plpython/plpy_util.c               |  9 ----
 src/pl/plpython/plpy_util.h               |  2 -
 src/pl/plpython/plpython.h                | 34 +------------
 contrib/hstore_plpython/hstore_plpython.c | 12 ++---
 contrib/jsonb_plpython/jsonb_plpython.c   | 11 ++---
 contrib/ltree_plpython/ltree_plpython.c   |  6 +--
 16 files changed, 81 insertions(+), 220 deletions(-)

diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c
index 08d8b607e38..6b6e7433453 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -40,7 +40,7 @@ static PyTypeObject PLy_CursorType = {
 	.tp_name = "PLyCursor",
 	.tp_basicsize = sizeof(PLyCursorObject),
 	.tp_dealloc = PLy_cursor_dealloc,
-	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_ITER,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_doc = PLy_cursor_doc,
 	.tp_iter = PyObject_SelfIter,
 	.tp_iternext = PLy_cursor_iternext,
@@ -150,7 +150,7 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
 
 	if (args)
 	{
-		if (!PySequence_Check(args) || PyString_Check(args) || PyUnicode_Check(args))
+		if (!PySequence_Check(args) || PyUnicode_Check(args))
 		{
 			PLy_exception_set(PyExc_TypeError, "plpy.cursor takes a sequence as its second argument");
 			return NULL;
@@ -169,7 +169,7 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
 
 		if (!so)
 			PLy_elog(ERROR, "could not execute plan");
-		sv = PyString_AsString(so);
+		sv = PLyUnicode_AsString(so);
 		PLy_exception_set_plural(PyExc_TypeError,
 								 "Expected sequence of %d argument, got %d: %s",
 								 "Expected sequence of %d arguments, got %d: %s",
@@ -410,7 +410,7 @@ PLy_cursor_fetch(PyObject *self, PyObject *args)
 		SPI_cursor_fetch(portal, true, count);
 
 		Py_DECREF(ret->status);
-		ret->status = PyInt_FromLong(SPI_OK_FETCH);
+		ret->status = PyLong_FromLong(SPI_OK_FETCH);
 
 		Py_DECREF(ret->nrows);
 		ret->nrows = PyLong_FromUnsignedLongLong(SPI_processed);
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index 224b8836fba..7c627eacfbf 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -193,24 +193,20 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
 	e_type_o = PyObject_GetAttrString(e, "__name__");
 	e_module_o = PyObject_GetAttrString(e, "__module__");
 	if (e_type_o)
-		e_type_s = PyString_AsString(e_type_o);
+		e_type_s = PLyUnicode_AsString(e_type_o);
 	if (e_type_s)
-		e_module_s = PyString_AsString(e_module_o);
+		e_module_s = PLyUnicode_AsString(e_module_o);
 
 	if (v && ((vob = PyObject_Str(v)) != NULL))
-		vstr = PyString_AsString(vob);
+		vstr = PLyUnicode_AsString(vob);
 	else
 		vstr = "unknown";
 
 	initStringInfo(&xstr);
 	if (!e_type_s || !e_module_s)
 	{
-		if (PyString_Check(e))
-			/* deprecated string exceptions */
-			appendStringInfoString(&xstr, PyString_AsString(e));
-		else
-			/* shouldn't happen */
-			appendStringInfoString(&xstr, "unrecognized exception");
+		/* shouldn't happen */
+		appendStringInfoString(&xstr, "unrecognized exception");
 	}
 	/* mimics behavior of traceback.format_exception_only */
 	else if (strcmp(e_module_s, "builtins") == 0
@@ -290,11 +286,11 @@ PLy_traceback(PyObject *e, PyObject *v, PyObject *tb,
 			if (*tb_depth == 1)
 				fname = "<module>";
 			else
-				fname = PyString_AsString(name);
+				fname = PLyUnicode_AsString(name);
 
 			proname = PLy_procedure_name(exec_ctx->curr_proc);
-			plain_filename = PyString_AsString(filename);
-			plain_lineno = PyInt_AsLong(lineno);
+			plain_filename = PLyUnicode_AsString(filename);
+			plain_lineno = PyLong_AsLong(lineno);
 
 			if (proname == NULL)
 				appendStringInfo(&tbstr, "\n  PL/Python anonymous code block, line %ld, in %s",
@@ -365,7 +361,7 @@ PLy_get_sqlerrcode(PyObject *exc, int *sqlerrcode)
 	if (sqlstate == NULL)
 		return;
 
-	buffer = PyString_AsString(sqlstate);
+	buffer = PLyUnicode_AsString(sqlstate);
 	if (strlen(buffer) == 5 &&
 		strspn(buffer, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5)
 	{
@@ -573,7 +569,7 @@ get_string_attr(PyObject *obj, char *attrname, char **str)
 	val = PyObject_GetAttrString(obj, attrname);
 	if (val != NULL && val != Py_None)
 	{
-		*str = pstrdup(PyString_AsString(val));
+		*str = pstrdup(PLyUnicode_AsString(val));
 	}
 	Py_XDECREF(val);
 }
@@ -589,7 +585,7 @@ set_string_attr(PyObject *obj, char *attrname, char *str)
 
 	if (str != NULL)
 	{
-		val = PyString_FromString(str);
+		val = PLyUnicode_FromString(str);
 		if (!val)
 			return false;
 	}
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index c6f6a6fbcca..150b3a5977f 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -294,7 +294,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
 /* trigger subhandler
  *
  * the python function is expected to return Py_None if the tuple is
- * acceptable and unmodified.  Otherwise it should return a PyString
+ * acceptable and unmodified.  Otherwise it should return a PyUnicode
  * object who's value is SKIP, or MODIFY.  SKIP means don't perform
  * this action.  MODIFY means the tuple has been modified, so update
  * tuple and perform action.  SKIP and MODIFY assume the trigger fires
@@ -360,9 +360,7 @@ PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
 		{
 			char	   *srv;
 
-			if (PyString_Check(plrv))
-				srv = PyString_AsString(plrv);
-			else if (PyUnicode_Check(plrv))
+			if (PyUnicode_Check(plrv))
 				srv = PLyUnicode_AsString(plrv);
 			else
 			{
@@ -700,35 +698,35 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 		if (!pltdata)
 			return NULL;
 
-		pltname = PyString_FromString(tdata->tg_trigger->tgname);
+		pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
 		PyDict_SetItemString(pltdata, "name", pltname);
 		Py_DECREF(pltname);
 
 		stroid = DatumGetCString(DirectFunctionCall1(oidout,
 													 ObjectIdGetDatum(tdata->tg_relation->rd_id)));
-		pltrelid = PyString_FromString(stroid);
+		pltrelid = PLyUnicode_FromString(stroid);
 		PyDict_SetItemString(pltdata, "relid", pltrelid);
 		Py_DECREF(pltrelid);
 		pfree(stroid);
 
 		stroid = SPI_getrelname(tdata->tg_relation);
-		plttablename = PyString_FromString(stroid);
+		plttablename = PLyUnicode_FromString(stroid);
 		PyDict_SetItemString(pltdata, "table_name", plttablename);
 		Py_DECREF(plttablename);
 		pfree(stroid);
 
 		stroid = SPI_getnspname(tdata->tg_relation);
-		plttableschema = PyString_FromString(stroid);
+		plttableschema = PLyUnicode_FromString(stroid);
 		PyDict_SetItemString(pltdata, "table_schema", plttableschema);
 		Py_DECREF(plttableschema);
 		pfree(stroid);
 
 		if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
-			pltwhen = PyString_FromString("BEFORE");
+			pltwhen = PLyUnicode_FromString("BEFORE");
 		else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
-			pltwhen = PyString_FromString("AFTER");
+			pltwhen = PLyUnicode_FromString("AFTER");
 		else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
-			pltwhen = PyString_FromString("INSTEAD OF");
+			pltwhen = PLyUnicode_FromString("INSTEAD OF");
 		else
 		{
 			elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
@@ -739,7 +737,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 
 		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
 		{
-			pltlevel = PyString_FromString("ROW");
+			pltlevel = PLyUnicode_FromString("ROW");
 			PyDict_SetItemString(pltdata, "level", pltlevel);
 			Py_DECREF(pltlevel);
 
@@ -750,7 +748,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 
 			if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
 			{
-				pltevent = PyString_FromString("INSERT");
+				pltevent = PLyUnicode_FromString("INSERT");
 
 				PyDict_SetItemString(pltdata, "old", Py_None);
 				pytnew = PLy_input_from_tuple(&proc->result_in,
@@ -763,7 +761,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			}
 			else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
 			{
-				pltevent = PyString_FromString("DELETE");
+				pltevent = PLyUnicode_FromString("DELETE");
 
 				PyDict_SetItemString(pltdata, "new", Py_None);
 				pytold = PLy_input_from_tuple(&proc->result_in,
@@ -776,7 +774,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			}
 			else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
 			{
-				pltevent = PyString_FromString("UPDATE");
+				pltevent = PLyUnicode_FromString("UPDATE");
 
 				pytnew = PLy_input_from_tuple(&proc->result_in,
 											  tdata->tg_newtuple,
@@ -803,7 +801,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 		}
 		else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
 		{
-			pltlevel = PyString_FromString("STATEMENT");
+			pltlevel = PLyUnicode_FromString("STATEMENT");
 			PyDict_SetItemString(pltdata, "level", pltlevel);
 			Py_DECREF(pltlevel);
 
@@ -812,13 +810,13 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			*rv = NULL;
 
 			if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
-				pltevent = PyString_FromString("INSERT");
+				pltevent = PLyUnicode_FromString("INSERT");
 			else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
-				pltevent = PyString_FromString("DELETE");
+				pltevent = PLyUnicode_FromString("DELETE");
 			else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
-				pltevent = PyString_FromString("UPDATE");
+				pltevent = PLyUnicode_FromString("UPDATE");
 			else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
-				pltevent = PyString_FromString("TRUNCATE");
+				pltevent = PLyUnicode_FromString("TRUNCATE");
 			else
 			{
 				elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
@@ -847,7 +845,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			}
 			for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
 			{
-				pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
+				pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
 
 				/*
 				 * stolen, don't Py_DECREF
@@ -931,9 +929,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
 			PLyObToDatum *att;
 
 			platt = PyList_GetItem(plkeys, i);
-			if (PyString_Check(platt))
-				plattstr = PyString_AsString(platt);
-			else if (PyUnicode_Check(platt))
+			if (PyUnicode_Check(platt))
 				plattstr = PLyUnicode_AsString(platt);
 			else
 			{
diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
index 3eedaa80da7..0bce1064951 100644
--- a/src/pl/plpython/plpy_main.c
+++ b/src/pl/plpython/plpy_main.c
@@ -28,27 +28,13 @@
  * exported functions
  */
 
-#if PY_MAJOR_VERSION >= 3
-/* Use separate names to reduce confusion */
-#define plpython_validator plpython3_validator
-#define plpython_call_handler plpython3_call_handler
-#define plpython_inline_handler plpython3_inline_handler
-#endif
-
 extern void _PG_init(void);
 
 PG_MODULE_MAGIC;
 
-PG_FUNCTION_INFO_V1(plpython_validator);
-PG_FUNCTION_INFO_V1(plpython_call_handler);
-PG_FUNCTION_INFO_V1(plpython_inline_handler);
-
-#if PY_MAJOR_VERSION < 3
-/* Define aliases plpython2_call_handler etc */
-PG_FUNCTION_INFO_V1(plpython2_validator);
-PG_FUNCTION_INFO_V1(plpython2_call_handler);
-PG_FUNCTION_INFO_V1(plpython2_inline_handler);
-#endif
+PG_FUNCTION_INFO_V1(plpython3_validator);
+PG_FUNCTION_INFO_V1(plpython3_call_handler);
+PG_FUNCTION_INFO_V1(plpython3_inline_handler);
 
 
 static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
@@ -82,6 +68,10 @@ _PG_init(void)
 	 * the actual failure for later, so that operations like pg_restore can
 	 * load more than one plpython library so long as they don't try to do
 	 * anything much with the language.
+	 *
+	 * While we only support Python 3 these days, somebody might create an
+	 * out-of-tree version adding back support for Python 2. Conflicts with
+	 * such an extension should be detected.
 	 */
 	bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
 	if (!(*bitmask_ptr))		/* am I the first? */
@@ -125,13 +115,9 @@ PLy_initialize(void)
 	if (inited)
 		return;
 
-#if PY_MAJOR_VERSION >= 3
 	PyImport_AppendInittab("plpy", PyInit_plpy);
-#endif
 	Py_Initialize();
-#if PY_MAJOR_VERSION >= 3
 	PyImport_ImportModule("plpy");
-#endif
 	PLy_init_interp();
 	PLy_init_plpy();
 	if (PyErr_Occurred())
@@ -171,7 +157,7 @@ PLy_init_interp(void)
 }
 
 Datum
-plpython_validator(PG_FUNCTION_ARGS)
+plpython3_validator(PG_FUNCTION_ARGS)
 {
 	Oid			funcoid = PG_GETARG_OID(0);
 	HeapTuple	tuple;
@@ -203,17 +189,8 @@ plpython_validator(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();
 }
 
-#if PY_MAJOR_VERSION < 3
 Datum
-plpython2_validator(PG_FUNCTION_ARGS)
-{
-	/* call plpython validator with our fcinfo so it gets our oid */
-	return plpython_validator(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
-Datum
-plpython_call_handler(PG_FUNCTION_ARGS)
+plpython3_call_handler(PG_FUNCTION_ARGS)
 {
 	bool		nonatomic;
 	Datum		retval;
@@ -284,16 +261,8 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 	return retval;
 }
 
-#if PY_MAJOR_VERSION < 3
 Datum
-plpython2_call_handler(PG_FUNCTION_ARGS)
-{
-	return plpython_call_handler(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
-Datum
-plpython_inline_handler(PG_FUNCTION_ARGS)
+plpython3_inline_handler(PG_FUNCTION_ARGS)
 {
 	LOCAL_FCINFO(fake_fcinfo, 0);
 	InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
@@ -368,14 +337,6 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();
 }
 
-#if PY_MAJOR_VERSION < 3
-Datum
-plpython2_inline_handler(PG_FUNCTION_ARGS)
-{
-	return plpython_inline_handler(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
 static bool
 PLy_procedure_is_trigger(Form_pg_proc procStruct)
 {
diff --git a/src/pl/plpython/plpy_planobject.c b/src/pl/plpython/plpy_planobject.c
index 5951d2a6ff5..ec2439c6a1f 100644
--- a/src/pl/plpython/plpy_planobject.c
+++ b/src/pl/plpython/plpy_planobject.c
@@ -119,7 +119,7 @@ PLy_plan_status(PyObject *self, PyObject *args)
 	{
 		Py_INCREF(Py_True);
 		return Py_True;
-		/* return PyInt_FromLong(self->status); */
+		/* return PyLong_FromLong(self->status); */
 	}
 	return NULL;
 }
diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c
index 907f89d1535..fa08f0dbfb3 100644
--- a/src/pl/plpython/plpy_plpymodule.c
+++ b/src/pl/plpython/plpy_plpymodule.c
@@ -107,7 +107,6 @@ static PyMethodDef PLy_exc_methods[] = {
 	{NULL, NULL, 0, NULL}
 };
 
-#if PY_MAJOR_VERSION >= 3
 static PyModuleDef PLy_module = {
 	PyModuleDef_HEAD_INIT,
 	.m_name = "plpy",
@@ -139,7 +138,6 @@ PyInit_plpy(void)
 
 	return m;
 }
-#endif							/* PY_MAJOR_VERSION >= 3 */
 
 void
 PLy_init_plpy(void)
@@ -148,10 +146,6 @@ PLy_init_plpy(void)
 			   *main_dict,
 			   *plpy_mod;
 
-#if PY_MAJOR_VERSION < 3
-	PyObject   *plpy;
-#endif
-
 	/*
 	 * initialize plpy module
 	 */
@@ -160,13 +154,7 @@ PLy_init_plpy(void)
 	PLy_subtransaction_init_type();
 	PLy_cursor_init_type();
 
-#if PY_MAJOR_VERSION >= 3
 	PyModule_Create(&PLy_module);
-	/* for Python 3 we initialized the exceptions in PyInit_plpy */
-#else
-	plpy = Py_InitModule("plpy", PLy_methods);
-	PLy_add_exceptions(plpy);
-#endif
 
 	/* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
 
@@ -189,11 +177,7 @@ PLy_add_exceptions(PyObject *plpy)
 	PyObject   *excmod;
 	HASHCTL		hash_ctl;
 
-#if PY_MAJOR_VERSION < 3
-	excmod = Py_InitModule("spiexceptions", PLy_exc_methods);
-#else
 	excmod = PyModule_Create(&PLy_exc_module);
-#endif
 	if (excmod == NULL)
 		PLy_elog(ERROR, "could not create the spiexceptions module");
 
@@ -268,7 +252,7 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base)
 		if (dict == NULL)
 			PLy_elog(ERROR, NULL);
 
-		sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate));
+		sqlstate = PLyUnicode_FromString(unpack_sql_state(exception_map[i].sqlstate));
 		if (sqlstate == NULL)
 			PLy_elog(ERROR, "could not generate SPI exceptions");
 
@@ -346,7 +330,7 @@ PLy_quote_literal(PyObject *self, PyObject *args)
 		return NULL;
 
 	quoted = quote_literal_cstr(str);
-	ret = PyString_FromString(quoted);
+	ret = PLyUnicode_FromString(quoted);
 	pfree(quoted);
 
 	return ret;
@@ -363,10 +347,10 @@ PLy_quote_nullable(PyObject *self, PyObject *args)
 		return NULL;
 
 	if (str == NULL)
-		return PyString_FromString("NULL");
+		return PLyUnicode_FromString("NULL");
 
 	quoted = quote_literal_cstr(str);
-	ret = PyString_FromString(quoted);
+	ret = PLyUnicode_FromString(quoted);
 	pfree(quoted);
 
 	return ret;
@@ -383,7 +367,7 @@ PLy_quote_ident(PyObject *self, PyObject *args)
 		return NULL;
 
 	quoted = quote_identifier(str);
-	ret = PyString_FromString(quoted);
+	ret = PLyUnicode_FromString(quoted);
 
 	return ret;
 }
@@ -400,7 +384,7 @@ object_to_string(PyObject *obj)
 		{
 			char	   *str;
 
-			str = pstrdup(PyString_AsString(so));
+			str = pstrdup(PLyUnicode_AsString(so));
 			Py_DECREF(so);
 
 			return str;
@@ -444,7 +428,7 @@ PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
 	else
 		so = PyObject_Str(args);
 
-	if (so == NULL || ((message = PyString_AsString(so)) == NULL))
+	if (so == NULL || ((message = PLyUnicode_AsString(so)) == NULL))
 	{
 		level = ERROR;
 		message = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog");
@@ -457,7 +441,7 @@ PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
 	{
 		while (PyDict_Next(kw, &pos, &key, &value))
 		{
-			char	   *keyword = PyString_AsString(key);
+			char	   *keyword = PLyUnicode_AsString(key);
 
 			if (strcmp(keyword, "message") == 0)
 			{
diff --git a/src/pl/plpython/plpy_plpymodule.h b/src/pl/plpython/plpy_plpymodule.h
index 54d78101ceb..ad6436aca78 100644
--- a/src/pl/plpython/plpy_plpymodule.h
+++ b/src/pl/plpython/plpy_plpymodule.h
@@ -11,9 +11,7 @@
 extern HTAB *PLy_spi_exceptions;
 
 
-#if PY_MAJOR_VERSION >= 3
 PyMODINIT_FUNC PyInit_plpy(void);
-#endif
 extern void PLy_init_plpy(void);
 
 #endif							/* PLPY_PLPYMODULE_H */
diff --git a/src/pl/plpython/plpy_resultobject.c b/src/pl/plpython/plpy_resultobject.c
index 54f39419c84..a8516b2db30 100644
--- a/src/pl/plpython/plpy_resultobject.c
+++ b/src/pl/plpython/plpy_resultobject.c
@@ -76,7 +76,7 @@ PLy_result_new(void)
 
 	Py_INCREF(Py_None);
 	ob->status = Py_None;
-	ob->nrows = PyInt_FromLong(-1);
+	ob->nrows = PyLong_FromLong(-1);
 	ob->rows = PyList_New(0);
 	ob->tupdesc = NULL;
 	if (!ob->rows)
@@ -125,7 +125,7 @@ PLy_result_colnames(PyObject *self, PyObject *unused)
 	{
 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-		PyList_SET_ITEM(list, i, PyString_FromString(NameStr(attr->attname)));
+		PyList_SET_ITEM(list, i, PLyUnicode_FromString(NameStr(attr->attname)));
 	}
 
 	return list;
@@ -151,7 +151,7 @@ PLy_result_coltypes(PyObject *self, PyObject *unused)
 	{
 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-		PyList_SET_ITEM(list, i, PyInt_FromLong(attr->atttypid));
+		PyList_SET_ITEM(list, i, PyLong_FromLong(attr->atttypid));
 	}
 
 	return list;
@@ -177,7 +177,7 @@ PLy_result_coltypmods(PyObject *self, PyObject *unused)
 	{
 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
 
-		PyList_SET_ITEM(list, i, PyInt_FromLong(attr->atttypmod));
+		PyList_SET_ITEM(list, i, PyLong_FromLong(attr->atttypmod));
 	}
 
 	return list;
@@ -226,19 +226,11 @@ PLy_result_str(PyObject *arg)
 {
 	PLyResultObject *ob = (PLyResultObject *) arg;
 
-#if PY_MAJOR_VERSION >= 3
 	return PyUnicode_FromFormat("<%s status=%S nrows=%S rows=%S>",
 								Py_TYPE(ob)->tp_name,
 								ob->status,
 								ob->nrows,
 								ob->rows);
-#else
-	return PyString_FromFormat("<%s status=%ld nrows=%ld rows=%s>",
-							   ob->ob_type->tp_name,
-							   PyInt_AsLong(ob->status),
-							   PyInt_AsLong(ob->nrows),
-							   PyString_AsString(PyObject_Str(ob->rows)));
-#endif
 }
 
 static PyObject *
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 86d70470a74..9a71a42c15f 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -90,9 +90,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
 			int32		typmod;
 
 			optr = PySequence_GetItem(list, i);
-			if (PyString_Check(optr))
-				sptr = PyString_AsString(optr);
-			else if (PyUnicode_Check(optr))
+			if (PyUnicode_Check(optr))
 				sptr = PLyUnicode_AsString(optr);
 			else
 			{
@@ -186,7 +184,7 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
 
 	if (list != NULL)
 	{
-		if (!PySequence_Check(list) || PyString_Check(list) || PyUnicode_Check(list))
+		if (!PySequence_Check(list) || PyUnicode_Check(list))
 		{
 			PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
 			return NULL;
@@ -205,7 +203,7 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
 
 		if (!so)
 			PLy_elog(ERROR, "could not execute plan");
-		sv = PyString_AsString(so);
+		sv = PLyUnicode_AsString(so);
 		PLy_exception_set_plural(PyExc_TypeError,
 								 "Expected sequence of %d argument, got %d: %s",
 								 "Expected sequence of %d arguments, got %d: %s",
@@ -360,7 +358,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
 		return NULL;
 	}
 	Py_DECREF(result->status);
-	result->status = PyInt_FromLong(status);
+	result->status = PyLong_FromLong(status);
 
 	if (status > 0 && tuptable == NULL)
 	{
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 5e807b139f1..bc348473d36 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -26,8 +26,8 @@ static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
-static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
-static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
+static PyObject *PLyLong_FromInt16(PLyDatumToOb *arg, Datum d);
+static PyObject *PLyLong_FromInt32(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyLong_FromOid(PLyDatumToOb *arg, Datum d);
 static PyObject *PLyBytes_FromBytea(PLyDatumToOb *arg, Datum d);
@@ -517,10 +517,10 @@ PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
 				arg->func = PLyDecimal_FromNumeric;
 				break;
 			case INT2OID:
-				arg->func = PLyInt_FromInt16;
+				arg->func = PLyLong_FromInt16;
 				break;
 			case INT4OID:
-				arg->func = PLyInt_FromInt32;
+				arg->func = PLyLong_FromInt32;
 				break;
 			case INT8OID:
 				arg->func = PLyLong_FromInt64;
@@ -600,15 +600,15 @@ PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
 }
 
 static PyObject *
-PLyInt_FromInt16(PLyDatumToOb *arg, Datum d)
+PLyLong_FromInt16(PLyDatumToOb *arg, Datum d)
 {
-	return PyInt_FromLong(DatumGetInt16(d));
+	return PyLong_FromLong(DatumGetInt16(d));
 }
 
 static PyObject *
-PLyInt_FromInt32(PLyDatumToOb *arg, Datum d)
+PLyLong_FromInt32(PLyDatumToOb *arg, Datum d)
 {
-	return PyInt_FromLong(DatumGetInt32(d));
+	return PyLong_FromLong(DatumGetInt32(d));
 }
 
 static PyObject *
@@ -641,7 +641,7 @@ static PyObject *
 PLyString_FromScalar(PLyDatumToOb *arg, Datum d)
 {
 	char	   *x = OutputFunctionCall(&arg->u.scalar.typfunc, d);
-	PyObject   *r = PyString_FromString(x);
+	PyObject   *r = PLyUnicode_FromString(x);
 
 	pfree(x);
 	return r;
@@ -954,7 +954,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
 	 * The string conversion case doesn't require a tupdesc, nor per-field
 	 * conversion data, so just go for it if that's the case to use.
 	 */
-	if (PyString_Check(plrv) || PyUnicode_Check(plrv))
+	if (PyUnicode_Check(plrv))
 		return PLyString_ToComposite(arg, plrv, inarray);
 
 	/*
@@ -1032,25 +1032,17 @@ PLyObject_AsString(PyObject *plrv)
 	else if (PyFloat_Check(plrv))
 	{
 		/* use repr() for floats, str() is lossy */
-#if PY_MAJOR_VERSION >= 3
 		PyObject   *s = PyObject_Repr(plrv);
 
 		plrv_bo = PLyUnicode_Bytes(s);
 		Py_XDECREF(s);
-#else
-		plrv_bo = PyObject_Repr(plrv);
-#endif
 	}
 	else
 	{
-#if PY_MAJOR_VERSION >= 3
 		PyObject   *s = PyObject_Str(plrv);
 
 		plrv_bo = PLyUnicode_Bytes(s);
 		Py_XDECREF(s);
-#else
-		plrv_bo = PyObject_Str(plrv);
-#endif
 	}
 	if (!plrv_bo)
 		PLy_elog(ERROR, "could not create string representation of Python object");
diff --git a/src/pl/plpython/plpy_util.c b/src/pl/plpython/plpy_util.c
index 4a7d7264d79..22e2a599ad9 100644
--- a/src/pl/plpython/plpy_util.c
+++ b/src/pl/plpython/plpy_util.c
@@ -78,12 +78,6 @@ PLyUnicode_Bytes(PyObject *unicode)
  * Convert a Python unicode object to a C string in PostgreSQL server
  * encoding.  No Python object reference is passed out of this
  * function.  The result is palloc'ed.
- *
- * Note that this function is disguised as PyString_AsString() when
- * using Python 3.  That function returns a pointer into the internal
- * memory of the argument, which isn't exactly the interface of this
- * function.  But in either case you get a rather short-lived
- * reference that you ought to better leave alone.
  */
 char *
 PLyUnicode_AsString(PyObject *unicode)
@@ -95,7 +89,6 @@ PLyUnicode_AsString(PyObject *unicode)
 	return rv;
 }
 
-#if PY_MAJOR_VERSION >= 3
 /*
  * Convert a C string in the PostgreSQL server encoding to a Python
  * unicode object.  Reference ownership is passed to the caller.
@@ -126,5 +119,3 @@ PLyUnicode_FromString(const char *s)
 {
 	return PLyUnicode_FromStringAndSize(s, strlen(s));
 }
-
-#endif							/* PY_MAJOR_VERSION >= 3 */
diff --git a/src/pl/plpython/plpy_util.h b/src/pl/plpython/plpy_util.h
index c9ba7edc0ec..7c6577925ea 100644
--- a/src/pl/plpython/plpy_util.h
+++ b/src/pl/plpython/plpy_util.h
@@ -11,9 +11,7 @@
 extern PyObject *PLyUnicode_Bytes(PyObject *unicode);
 extern char *PLyUnicode_AsString(PyObject *unicode);
 
-#if PY_MAJOR_VERSION >= 3
 extern PyObject *PLyUnicode_FromString(const char *s);
 extern PyObject *PLyUnicode_FromStringAndSize(const char *s, Py_ssize_t size);
-#endif
 
 #endif							/* PLPY_UTIL_H */
diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h
index 05e4362dab9..2a0c9bf0361 100644
--- a/src/pl/plpython/plpython.h
+++ b/src/pl/plpython/plpython.h
@@ -59,37 +59,6 @@
 #include <Python.h>
 #endif
 
-/*
- * Python 2/3 strings/unicode/bytes handling.  Python 2 has strings
- * and unicode, Python 3 has strings, which are unicode on the C
- * level, and bytes.  The porting convention, which is similarly used
- * in Python 2.6, is that "Unicode" is always unicode, and "Bytes" are
- * bytes in Python 3 and strings in Python 2.  Since we keep
- * supporting Python 2 and its usual strings, we provide a
- * compatibility layer for Python 3 that when asked to convert a C
- * string to a Python string it converts the C string from the
- * PostgreSQL server encoding to a Python Unicode object.
- */
-#if PY_MAJOR_VERSION >= 3
-#define PyString_Check(x) 0
-#define PyString_AsString(x) PLyUnicode_AsString(x)
-#define PyString_FromString(x) PLyUnicode_FromString(x)
-#define PyString_FromStringAndSize(x, size) PLyUnicode_FromStringAndSize(x, size)
-#endif
-
-/*
- * Python 3 only has long.
- */
-#if PY_MAJOR_VERSION >= 3
-#define PyInt_FromLong(x) PyLong_FromLong(x)
-#define PyInt_AsLong(x) PyLong_AsLong(x)
-#endif
-
-/* Python 3 removed the Py_TPFLAGS_HAVE_ITER flag */
-#if PY_MAJOR_VERSION >= 3
-#define Py_TPFLAGS_HAVE_ITER 0
-#endif
-
 /* define our text domain for translations */
 #undef TEXTDOMAIN
 #define TEXTDOMAIN PG_TEXTDOMAIN("plpython")
@@ -130,8 +99,7 @@
 #define printf(...)		pg_printf(__VA_ARGS__)
 
 /*
- * Used throughout, and also by the Python 2/3 porting layer, so it's easier to
- * just include it everywhere.
+ * Used throughout, so it's easier to just include it everywhere.
  */
 #include "plpy_util.h"
 
diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c
index 39bad558023..889ece315df 100644
--- a/contrib/hstore_plpython/hstore_plpython.c
+++ b/contrib/hstore_plpython/hstore_plpython.c
@@ -12,10 +12,8 @@ extern void _PG_init(void);
 /* Linkage to functions in plpython module */
 typedef char *(*PLyObject_AsString_t) (PyObject *plrv);
 static PLyObject_AsString_t PLyObject_AsString_p;
-#if PY_MAJOR_VERSION >= 3
 typedef PyObject *(*PLyUnicode_FromStringAndSize_t) (const char *s, Py_ssize_t size);
 static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
-#endif
 
 /* Linkage to functions in hstore module */
 typedef HStore *(*hstoreUpgrade_t) (Datum orig);
@@ -41,12 +39,10 @@ _PG_init(void)
 	PLyObject_AsString_p = (PLyObject_AsString_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString",
 							   true, NULL);
-#if PY_MAJOR_VERSION >= 3
 	AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t);
 	PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
 							   true, NULL);
-#endif
 	AssertVariableIsOfType(&hstoreUpgrade, hstoreUpgrade_t);
 	hstoreUpgrade_p = (hstoreUpgrade_t)
 		load_external_function("$libdir/hstore", "hstoreUpgrade",
@@ -102,16 +98,16 @@ hstore_to_plpython(PG_FUNCTION_ARGS)
 	{
 		PyObject   *key;
 
-		key = PyString_FromStringAndSize(HSTORE_KEY(entries, base, i),
-										 HSTORE_KEYLEN(entries, i));
+		key = PLyUnicode_FromStringAndSize(HSTORE_KEY(entries, base, i),
+										  HSTORE_KEYLEN(entries, i));
 		if (HSTORE_VALISNULL(entries, i))
 			PyDict_SetItem(dict, key, Py_None);
 		else
 		{
 			PyObject   *value;
 
-			value = PyString_FromStringAndSize(HSTORE_VAL(entries, base, i),
-											   HSTORE_VALLEN(entries, i));
+			value = PLyUnicode_FromStringAndSize(HSTORE_VAL(entries, base, i),
+												HSTORE_VALLEN(entries, i));
 			PyDict_SetItem(dict, key, value);
 			Py_XDECREF(value);
 		}
diff --git a/contrib/jsonb_plpython/jsonb_plpython.c b/contrib/jsonb_plpython/jsonb_plpython.c
index 836c1787706..e6a87e557a9 100644
--- a/contrib/jsonb_plpython/jsonb_plpython.c
+++ b/contrib/jsonb_plpython/jsonb_plpython.c
@@ -28,11 +28,9 @@ static PyObject *PLyObject_FromJsonbContainer(JsonbContainer *jsonb);
 static JsonbValue *PLyObject_ToJsonbValue(PyObject *obj,
 										  JsonbParseState **jsonb_state, bool is_elem);
 
-#if PY_MAJOR_VERSION >= 3
 typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
 			(const char *s, Py_ssize_t size);
 static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
-#endif
 
 /*
  * Module initialize function: fetch function pointers for cross-module calls.
@@ -45,13 +43,10 @@ _PG_init(void)
 	PLyObject_AsString_p = (PLyObject_AsString_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString",
 							   true, NULL);
-#if PY_MAJOR_VERSION >= 3
 	AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t);
 	PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
 							   true, NULL);
-#endif
-
 	AssertVariableIsOfType(&PLy_elog_impl, PLy_elog_impl_t);
 	PLy_elog_impl_p = (PLy_elog_impl_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLy_elog_impl",
@@ -74,7 +69,7 @@ PLyString_FromJsonbValue(JsonbValue *jbv)
 {
 	Assert(jbv->type == jbvString);
 
-	return PyString_FromStringAndSize(jbv->val.string.val, jbv->val.string.len);
+	return PLyUnicode_FromStringAndSize(jbv->val.string.val, jbv->val.string.len);
 }
 
 /*
@@ -415,7 +410,7 @@ PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_ele
 {
 	JsonbValue *out;
 
-	if (!(PyString_Check(obj) || PyUnicode_Check(obj)))
+	if (!PyUnicode_Check(obj))
 	{
 		if (PySequence_Check(obj))
 			return PLySequence_ToJsonbValue(obj, jsonb_state);
@@ -427,7 +422,7 @@ PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_ele
 
 	if (obj == Py_None)
 		out->type = jbvNull;
-	else if (PyString_Check(obj) || PyUnicode_Check(obj))
+	else if (PyUnicode_Check(obj))
 		PLyString_ToJsonbValue(obj, out);
 
 	/*
diff --git a/contrib/ltree_plpython/ltree_plpython.c b/contrib/ltree_plpython/ltree_plpython.c
index 1570e77dd9f..7431a1150a9 100644
--- a/contrib/ltree_plpython/ltree_plpython.c
+++ b/contrib/ltree_plpython/ltree_plpython.c
@@ -9,10 +9,8 @@ PG_MODULE_MAGIC;
 extern void _PG_init(void);
 
 /* Linkage to functions in plpython module */
-#if PY_MAJOR_VERSION >= 3
 typedef PyObject *(*PLyUnicode_FromStringAndSize_t) (const char *s, Py_ssize_t size);
 static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
-#endif
 
 
 /*
@@ -22,12 +20,10 @@ void
 _PG_init(void)
 {
 	/* Asserts verify that typedefs above match original declarations */
-#if PY_MAJOR_VERSION >= 3
 	AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t);
 	PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
 		load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
 							   true, NULL);
-#endif
 }
 
 
@@ -54,7 +50,7 @@ ltree_to_plpython(PG_FUNCTION_ARGS)
 	curlevel = LTREE_FIRST(in);
 	for (i = 0; i < in->numlevel; i++)
 	{
-		PyList_SetItem(list, i, PyString_FromStringAndSize(curlevel->name, curlevel->len));
+		PyList_SetItem(list, i, PLyUnicode_FromStringAndSize(curlevel->name, curlevel->len));
 		curlevel = LEVEL_NEXT(curlevel);
 	}
 
-- 
2.35.1.354.g715d08a9e5

