From 3a4a33ad49e7887b104a29323e4ea625d164a139 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sat, 2 Jul 2016 22:53:14 -0400
Subject: [PATCH] PL/Python: Report argument parsing errors using exceptions

Instead of calling PLy_elog() for reporting Python argument parsing
errors, generate appropriate exceptions.  This matches the existing plpy
functions and is more consistent with the behavior of the Python
argument parsing routines.
---
 src/pl/plpython/expected/plpython_ereport.out | 28 +++++++++++++------
 src/pl/plpython/plpy_plpymodule.c             | 23 +++++++++++----
 2 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/src/pl/plpython/expected/plpython_ereport.out b/src/pl/plpython/expected/plpython_ereport.out
index 43ce035de61..13bd0ab3352 100644
--- a/src/pl/plpython/expected/plpython_ereport.out
+++ b/src/pl/plpython/expected/plpython_ereport.out
@@ -56,17 +56,29 @@ INFO:  other types
 DETAIL:  ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
 -- should fail
 DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
-ERROR:  invalid SQLSTATE code
-CONTEXT:  PL/Python anonymous code block
+ERROR:  ValueError: invalid SQLSTATE code
+CONTEXT:  Traceback (most recent call last):
+  PL/Python anonymous code block, line 1, in <module>
+    plpy.info('wrong sqlstate', sqlstate='54444A') 
+PL/Python anonymous code block
 DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
-ERROR:  'blabla' is an invalid keyword argument for this function
-CONTEXT:  PL/Python anonymous code block
+ERROR:  TypeError: 'blabla' is an invalid keyword argument for this function
+CONTEXT:  Traceback (most recent call last):
+  PL/Python anonymous code block, line 1, in <module>
+    plpy.info('unsupported argument', blabla='fooboo') 
+PL/Python anonymous code block
 DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
-ERROR:  the message is already specified
-CONTEXT:  PL/Python anonymous code block
+ERROR:  TypeError: Argument 'message' given by name and position
+CONTEXT:  Traceback (most recent call last):
+  PL/Python anonymous code block, line 1, in <module>
+    plpy.info('first message', message='second message') 
+PL/Python anonymous code block
 DO $$ plpy.info('first message', 'second message', message='third message') $$ LANGUAGE plpythonu;
-ERROR:  the message is already specified
-CONTEXT:  PL/Python anonymous code block
+ERROR:  TypeError: Argument 'message' given by name and position
+CONTEXT:  Traceback (most recent call last):
+  PL/Python anonymous code block, line 1, in <module>
+    plpy.info('first message', 'second message', message='third message') 
+PL/Python anonymous code block
 -- raise exception in python, handle exception in plgsql
 CREATE OR REPLACE FUNCTION raise_exception(_message text, _detail text DEFAULT NULL, _hint text DEFAULT NULL,
                                            _sqlstate text DEFAULT NULL,
diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c
index 1fcb28b147a..4dd7949a9c9 100644
--- a/src/pl/plpython/plpy_plpymodule.c
+++ b/src/pl/plpython/plpy_plpymodule.c
@@ -444,7 +444,10 @@ PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
 			{
 				/* the message should not be overwriten */
 				if (PyTuple_Size(args) != 0)
-					PLy_elog(ERROR, "the message is already specified");
+				{
+					PLy_exception_set(PyExc_TypeError, "Argument 'message' given by name and position");
+					return NULL;
+				}
 
 				if (message)
 					pfree(message);
@@ -467,18 +470,28 @@ PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
 			else if (strcmp(keyword, "constraint_name") == 0)
 				constraint_name = object_to_string(value);
 			else
-				PLy_elog(ERROR, "'%s' is an invalid keyword argument for this function",
-						 keyword);
+			{
+				PLy_exception_set(PyExc_TypeError,
+								  "'%s' is an invalid keyword argument for this function",
+								  keyword);
+				return NULL;
+			}
 		}
 	}
 
 	if (sqlstatestr != NULL)
 	{
 		if (strlen(sqlstatestr) != 5)
-			PLy_elog(ERROR, "invalid SQLSTATE code");
+		{
+			PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code");
+			return NULL;
+		}
 
 		if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
-			PLy_elog(ERROR, "invalid SQLSTATE code");
+		{
+			PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code");
+			return NULL;
+		}
 
 		sqlstate = MAKE_SQLSTATE(sqlstatestr[0],
 								 sqlstatestr[1],
-- 
GitLab