verbose mode for pg_input_error_message?

Started by Andrew Dunstanabout 3 years ago17 messages
#1Andrew Dunstan
andrew@dunslane.net

I've been wondering if it might be a good idea to have a third parameter
for pg_input_error_message() which would default to false, but which if
true would cause it to emit the detail and hint fields, if any,  as well
as the message field from the error_data.

Thoughts?

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andrew Dunstan (#1)
Re: verbose mode for pg_input_error_message?

Andrew Dunstan <andrew@dunslane.net> writes:

I've been wondering if it might be a good idea to have a third parameter
for pg_input_error_message() which would default to false, but which if
true would cause it to emit the detail and hint fields, if any, as well
as the message field from the error_data.

I don't think that just concatenating those strings would make for a
pleasant API. More sensible, perhaps, to have a separate function
that returns a record. Or we could redefine the existing function
that way, but I suspect that "just the primary error" will be a
principal use-case.

Being able to get the SQLSTATE is likely to be interesting too.

regards, tom lane

#3Andrew Dunstan
andrew@dunslane.net
In reply to: Tom Lane (#2)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On 2023-01-02 Mo 10:44, Tom Lane wrote:

Andrew Dunstan <andrew@dunslane.net> writes:

I've been wondering if it might be a good idea to have a third parameter
for pg_input_error_message() which would default to false, but which if
true would cause it to emit the detail and hint fields, if any, as well
as the message field from the error_data.

I don't think that just concatenating those strings would make for a
pleasant API. More sensible, perhaps, to have a separate function
that returns a record. Or we could redefine the existing function
that way, but I suspect that "just the primary error" will be a
principal use-case.

Being able to get the SQLSTATE is likely to be interesting too.

OK, here's a patch along those lines.

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

Attachments:

pg_input_error_detail.patchtext/x-patch; charset=UTF-8; name=pg_input_error_detail.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3bf8d021c3..d44d78fa67 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24768,6 +24768,40 @@ SELECT collation for ('foo' COLLATE "de_DE");
          <returnvalue>numeric field overflow</returnvalue>
        </para></entry>
       </row>
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_input_error_detail</primary>
+        </indexterm>
+        <function>pg_input_error_detail</function> (
+          <parameter>string</parameter> <type>text</type>,
+          <parameter>type</parameter> <type>text</type>
+        )
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
+       </para>
+       <para>
+        Tests whether the given <parameter>string</parameter> is valid
+        input for the specified data type; if not, return the details of
+        the error that would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
+        for <function>pg_input_is_valid</function>.
+       </para>
+       <para>
+        This function will only work as desired if the data type's input
+        function has been updated to report invalid input as
+        a <quote>soft</quote> error.  Otherwise, invalid input will abort
+        the transaction, just as if the string had been cast to the type
+        directly.
+        </para>
+        <para>
+         <literal>to_json(pg_input_error_detail('{1,2', 'integer[]'))</literal>
+         <returnvalue>{"message":"malformed array literal: \"{1,2\"","detail":"Unexpected end of input.","hint":null,"sql_error_code":"22P02"}</returnvalue>
+        </para></entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 220ddb8c01..622b534532 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -688,6 +688,63 @@ pg_input_error_message(PG_FUNCTION_ARGS)
 	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
 }
 
+/*
+ * pg_input_error_detail - test whether string is valid input for datatype.
+ *
+ * Returns NULL data if OK, else the primary message, detail message,
+ * hint message and sql error code from the error.
+ *
+ * This will only work usefully if the datatype's input function has been
+ * updated to return "soft" errors via errsave/ereturn.
+ */
+Datum
+pg_input_error_detail(PG_FUNCTION_ARGS)
+{
+	text	   *txt = PG_GETARG_TEXT_PP(0);
+	text	   *typname = PG_GETARG_TEXT_PP(1);
+	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	/* Enable details_wanted */
+	escontext.details_wanted = true;
+
+	if (pg_input_is_valid_common(fcinfo, txt, typname,
+								 &escontext))
+	{
+		memset(isnull,true,sizeof(isnull));
+	}
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
+
+		memset(isnull, false, sizeof(isnull));
+
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
+
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
+
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
+
 /* Common subroutine for the above */
 static bool
 pg_input_is_valid_common(FunctionCallInfo fcinfo,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 7be9a50147..dfc0846f6f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7081,6 +7081,14 @@
   descr => 'get error message if string is not valid input for data type',
   proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
   proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+{ oid => '8052',
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_detail', provolatile => 's',
+  prorettype => 'record', proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_detail' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..9ee081b014 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -207,6 +207,12 @@ SELECT pg_input_error_message('{1,zed}', 'integer[]');
  invalid input syntax for type integer: "zed"
 (1 row)
 
+SELECT to_json(pg_input_error_detail('{1,2','integer[]'));
+                                                         to_json                                                          
+--------------------------------------------------------------------------------------------------------------------------
+ {"message":"malformed array literal: \"{1,2\"","detail":"Unexpected end of input.","hint":null,"sql_error_code":"22P02"}
+(1 row)
+
 -- test mixed slice/scalar subscripting
 select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
            int4            
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..4f95ebcc29 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -532,6 +532,18 @@ SELECT pg_input_error_message('no_such_type', 'regtype');
  type "no_such_type" does not exist
 (1 row)
 
+SELECT to_json(pg_input_error_detail('+(int4)','regoperator'));
+                                                                   to_json                                                                   
+---------------------------------------------------------------------------------------------------------------------------------------------
+ {"message":"missing argument","detail":null,"hint":"Use NONE to denote the missing argument of a unary operator.","sql_error_code":"42P02"}
+(1 row)
+
+SELECT to_json(pg_input_error_detail('+(int4,int4,int4)','regoperator'));
+                                                          to_json                                                          
+---------------------------------------------------------------------------------------------------------------------------
+ {"message":"too many arguments","detail":null,"hint":"Provide two argument types for operator.","sql_error_code":"54023"}
+(1 row)
+
 -- Some cases that should be soft errors, but are not yet
 SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
 ERROR:  syntax error at or near "type"
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 38e8dd440b..db29ccb50e 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -118,6 +118,7 @@ SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
 SELECT pg_input_is_valid('{1,2', 'integer[]');
 SELECT pg_input_is_valid('{1,zed}', 'integer[]');
 SELECT pg_input_error_message('{1,zed}', 'integer[]');
+SELECT to_json(pg_input_error_detail('{1,2','integer[]'));
 
 -- test mixed slice/scalar subscripting
 select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index 2cb8c9a253..34033a64e1 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -139,6 +139,8 @@ SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
 SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
 SELECT pg_input_error_message('regress_regrole_test', 'regrole');
 SELECT pg_input_error_message('no_such_type', 'regtype');
+SELECT to_json(pg_input_error_detail('+(int4)','regoperator'));
+SELECT to_json(pg_input_error_detail('+(int4,int4,int4)','regoperator'));
 
 -- Some cases that should be soft errors, but are not yet
 SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
#4Nathan Bossart
nathandbossart@gmail.com
In reply to: Andrew Dunstan (#3)
Re: verbose mode for pg_input_error_message?

On Wed, Jan 04, 2023 at 04:18:59PM -0500, Andrew Dunstan wrote:

On 2023-01-02 Mo 10:44, Tom Lane wrote:

I don't think that just concatenating those strings would make for a
pleasant API. More sensible, perhaps, to have a separate function
that returns a record. Or we could redefine the existing function
that way, but I suspect that "just the primary error" will be a
principal use-case.

Being able to get the SQLSTATE is likely to be interesting too.

OK, here's a patch along those lines.

My vote would be to redefine the existing pg_input_error_message() function
to return a record, but I recognize that this would inflate the patch quite
a bit due to all the existing uses in the tests. If this is the only
argument against this approach, I'm happy to help with the patch.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

#5Nathan Bossart
nathandbossart@gmail.com
In reply to: Nathan Bossart (#4)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On Tue, Jan 10, 2023 at 03:41:12PM -0800, Nathan Bossart wrote:

My vote would be to redefine the existing pg_input_error_message() function
to return a record, but I recognize that this would inflate the patch quite
a bit due to all the existing uses in the tests. If this is the only
argument against this approach, I'm happy to help with the patch.

Here's an attempt at this.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-add-details-to-pg_input_error_message.patchtext/x-diff; charset=us-asciiDownload
From 1b92850e7b8811a1e1114a18359d01d33089c0bf Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Thu, 23 Feb 2023 10:31:24 -0800
Subject: [PATCH v2 1/1] add details to pg_input_error_message

---
 contrib/cube/expected/cube.out                |  6 +-
 contrib/hstore/expected/hstore.out            | 12 +--
 contrib/intarray/expected/_int.out            | 10 +--
 contrib/isn/expected/isn.out                  | 10 +--
 contrib/ltree/expected/ltree.out              | 20 ++---
 contrib/seg/expected/seg.out                  | 16 ++--
 doc/src/sgml/func.sgml                        | 29 ++++---
 src/backend/utils/adt/misc.c                  | 38 +++++++--
 src/include/catalog/pg_proc.dat               | 10 ++-
 src/test/regress/expected/arrays.out          |  6 +-
 src/test/regress/expected/bit.out             | 30 +++----
 src/test/regress/expected/boolean.out         |  6 +-
 src/test/regress/expected/box.out             | 12 +--
 src/test/regress/expected/char_1.out          |  6 +-
 src/test/regress/expected/date.out            | 12 +--
 src/test/regress/expected/domain.out          | 24 +++---
 src/test/regress/expected/enum.out            | 12 +--
 src/test/regress/expected/float4.out          |  6 +-
 src/test/regress/expected/float8.out          |  6 +-
 src/test/regress/expected/geometry.out        | 12 +--
 src/test/regress/expected/inet.out            | 18 ++---
 src/test/regress/expected/int2.out            | 18 ++---
 src/test/regress/expected/int4.out            |  6 +-
 src/test/regress/expected/int8.out            |  6 +-
 src/test/regress/expected/interval.out        | 12 +--
 src/test/regress/expected/json.out            |  6 +-
 src/test/regress/expected/json_encoding.out   |  2 +-
 src/test/regress/expected/jsonb.out           | 12 +--
 src/test/regress/expected/jsonpath.out        | 14 ++--
 src/test/regress/expected/line.out            | 30 +++----
 src/test/regress/expected/lseg.out            |  6 +-
 src/test/regress/expected/macaddr.out         | 12 +--
 src/test/regress/expected/macaddr8.out        | 12 +--
 src/test/regress/expected/money.out           | 12 +--
 src/test/regress/expected/multirangetypes.out | 12 +--
 src/test/regress/expected/numeric.out         | 18 ++---
 src/test/regress/expected/oid.out             | 24 +++---
 src/test/regress/expected/path.out            | 12 +--
 src/test/regress/expected/pg_lsn.out          |  6 +-
 src/test/regress/expected/point.out           |  6 +-
 src/test/regress/expected/polygon.out         | 12 +--
 src/test/regress/expected/privileges.out      | 18 ++---
 src/test/regress/expected/rangetypes.out      | 30 +++----
 src/test/regress/expected/regproc.out         | 78 +++++++++----------
 src/test/regress/expected/rowtypes.out        | 12 +--
 src/test/regress/expected/strings.out         | 18 ++---
 src/test/regress/expected/tid.out             | 12 +--
 src/test/regress/expected/time.out            | 12 +--
 src/test/regress/expected/timestamp.out       | 12 +--
 src/test/regress/expected/timestamptz.out     | 12 +--
 src/test/regress/expected/timetz.out          | 12 +--
 src/test/regress/expected/tstypes.out         | 18 ++---
 src/test/regress/expected/uuid.out            |  6 +-
 src/test/regress/expected/varchar_1.out       |  6 +-
 src/test/regress/expected/xid.out             | 24 +++---
 src/test/regress/expected/xml.out             | 20 +++--
 56 files changed, 438 insertions(+), 391 deletions(-)

diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index dc23e5ccc0..3bb42b063b 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -345,9 +345,9 @@ SELECT pg_input_is_valid('-1e-700', 'cube');
 (1 row)
 
 SELECT pg_input_error_message('-1e-700', 'cube');
-               pg_input_error_message                
------------------------------------------------------
- "-1e-700" is out of range for type double precision
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("""-1e-700"" is out of range for type double precision",,,22003)
 (1 row)
 
 --
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index d6faa91867..d58fee585e 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -266,15 +266,15 @@ select pg_input_is_valid('a=b', 'hstore');
 (1 row)
 
 select pg_input_error_message('a=b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "b" at position 2
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""b"" at position 2",,,42601)
 (1 row)
 
 select pg_input_error_message(' =>b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "=" at position 1
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""="" at position 1",,,42601)
 (1 row)
 
 -- -> operator
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index c953065a5c..73dfea605a 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -406,11 +406,11 @@ FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
       AS a(str);
-    query_int    | ok |    errmsg    
------------------+----+--------------
- 1&(2&(4&(5|6))) | t  | 
- 1#(2&(4&(5&6))) | f  | syntax error
- foo             | f  | syntax error
+    query_int    | ok |          errmsg          
+-----------------+----+--------------------------
+ 1&(2&(4&(5|6))) | t  | (,,,)
+ 1#(2&(4&(5&6))) | f  | ("syntax error",,,42601)
+ foo             | f  | ("syntax error",,,42601)
 (3 rows)
 
 CREATE TABLE test__int( a int[] );
diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out
index 72171b2790..cbe4166fd0 100644
--- a/contrib/isn/expected/isn.out
+++ b/contrib/isn/expected/isn.out
@@ -268,11 +268,11 @@ FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
       AS a(str,typ);
-      isn      | type  | ok |                         errmsg                         
----------------+-------+----+--------------------------------------------------------
- 9780123456786 | UPC   | f  | cannot cast ISBN to UPC for number: "9780123456786"
- postgresql... | EAN13 | f  | invalid input syntax for EAN13 number: "postgresql..."
- 9771234567003 | ISSN  | t  | 
+      isn      | type  | ok |                                errmsg                                
+---------------+-------+----+----------------------------------------------------------------------
+ 9780123456786 | UPC   | f  | ("cannot cast ISBN to UPC for number: ""9780123456786""",,,22P02)
+ postgresql... | EAN13 | f  | ("invalid input syntax for EAN13 number: ""postgresql...""",,,22P02)
+ 9771234567003 | ISSN  | t  | (,,,)
 (3 rows)
 
 --
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index d2a53b9f0c..cf925b2469 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -8111,15 +8111,15 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
       AS a(str,typ);
-     value      |   type    | ok |               errmsg               
-----------------+-----------+----+------------------------------------
- .2.3           | ltree     | f  | ltree syntax error at character 1
- 1.2.           | ltree     | f  | ltree syntax error
- 1.2.3          | ltree     | t  | 
- @.2.3          | lquery    | f  | lquery syntax error at character 1
-  2.3           | lquery    | f  | lquery syntax error at character 1
- 1.2.3          | lquery    | t  | 
- $tree & aWdf@* | ltxtquery | f  | operand syntax error
- !tree & aWdf@* | ltxtquery | t  | 
+     value      |   type    | ok |                          errmsg                          
+----------------+-----------+----+----------------------------------------------------------
+ .2.3           | ltree     | f  | ("ltree syntax error at character 1",,,42601)
+ 1.2.           | ltree     | f  | ("ltree syntax error","Unexpected end of input.",,42601)
+ 1.2.3          | ltree     | t  | (,,,)
+ @.2.3          | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+  2.3           | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+ 1.2.3          | lquery    | t  | (,,,)
+ $tree & aWdf@* | ltxtquery | f  | ("operand syntax error",,,42601)
+ !tree & aWdf@* | ltxtquery | t  | (,,,)
 (8 rows)
 
diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 7a06113ed8..4b09bd1d4f 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1283,13 +1283,13 @@ FROM unnest(ARRAY['-1 .. 1'::text,
                   'ABC',
                   '1 e7',
                   '1e700']) str;
-   seg    | ok |                errmsg                 
-----------+----+---------------------------------------
- -1 .. 1  | t  | 
- 100(+-)1 | t  | 
-          | f  | bad seg representation
- ABC      | f  | bad seg representation
- 1 e7     | f  | bad seg representation
- 1e700    | f  | "1e700" is out of range for type real
+   seg    | ok |                              errmsg                               
+----------+----+-------------------------------------------------------------------
+ -1 .. 1  | t  | (,,,)
+ 100(+-)1 | t  | (,,,)
+          | f  | ("bad seg representation","syntax error at end of input",,42601)
+ ABC      | f  | ("bad seg representation","syntax error at or near ""A""",,42601)
+ 1 e7     | f  | ("bad seg representation","syntax error at or near ""e""",,42601)
+ 1e700    | f  | ("""1e700"" is out of range for type real",,,22003)
 (6 rows)
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0cbdf63632..76dade49db 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24781,13 +24781,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
           <parameter>string</parameter> <type>text</type>,
           <parameter>type</parameter> <type>text</type>
         )
-        <returnvalue>text</returnvalue>
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
        </para>
        <para>
         Tests whether the given <parameter>string</parameter> is valid
-        input for the specified data type; if not, return the error
-        message that would have been thrown.  If the input is valid, the
-        result is NULL.  The inputs are the same as
+        input for the specified data type; if not, return the details of
+        the error would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
         for <function>pg_input_is_valid</function>.
        </para>
        <para>
@@ -24798,12 +24802,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
         directly.
         </para>
         <para>
-         <literal>pg_input_error_message('42000000000', 'integer')</literal>
-         <returnvalue>value "42000000000" is out of range for type integer</returnvalue>
-        </para>
-        <para>
-         <literal>pg_input_error_message('1234.567', 'numeric(7,4)')</literal>
-         <returnvalue>numeric field overflow</returnvalue>
+<programlisting>
+SELECT * FROM pg_input_error_message('42000000000', 'integer');
+                       message                        | detail | hint | sql_error_code
+------------------------------------------------------+--------+------+----------------
+ value "42000000000" is out of range for type integer |        |      | 22003
+
+SELECT * FROM pg_input_error_message('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
+</programlisting>
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index f95256efd3..a4f4b7fb90 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -662,7 +662,8 @@ pg_input_is_valid(PG_FUNCTION_ARGS)
 /*
  * pg_input_error_message - test whether string is valid input for datatype.
  *
- * Returns NULL if OK, else the primary message string from the error.
+ * Returns NULL if OK, else the primary message, detail message, hint message,
+ * and sql error code from the error.
  *
  * This will only work usefully if the datatype's input function has been
  * updated to return "soft" errors via errsave/ereturn.
@@ -673,19 +674,44 @@ pg_input_error_message(PG_FUNCTION_ARGS)
 	text	   *txt = PG_GETARG_TEXT_PP(0);
 	text	   *typname = PG_GETARG_TEXT_PP(1);
 	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
 	/* Enable details_wanted */
 	escontext.details_wanted = true;
 
 	if (pg_input_is_valid_common(fcinfo, txt, typname,
 								 &escontext))
-		PG_RETURN_NULL();
+		memset(isnull, true, sizeof(isnull));
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
+
+		memset(isnull, false, sizeof(isnull));
+
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
 
-	Assert(escontext.error_occurred);
-	Assert(escontext.error_data != NULL);
-	Assert(escontext.error_data->message != NULL);
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
 
-	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /* Common subroutine for the above */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e2a7642a2b..ecb5df2e53 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7118,9 +7118,13 @@
   proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool',
   proargtypes => 'text text', prosrc => 'pg_input_is_valid' },
 { oid => '8051',
-  descr => 'get error message if string is not valid input for data type',
-  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
-  proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'record',
+  proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_message' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..0e6a50dbca 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -202,9 +202,9 @@ SELECT pg_input_is_valid('{1,zed}', 'integer[]');
 (1 row)
 
 SELECT pg_input_error_message('{1,zed}', 'integer[]');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 -- test mixed slice/scalar subscripting
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 209044713c..1b88327cb6 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -754,9 +754,9 @@ SELECT pg_input_is_valid('01010001', 'bit(10)');
 (1 row)
 
 SELECT pg_input_error_message('01010001', 'bit(10)');
-             pg_input_error_message              
--------------------------------------------------
- bit string length 8 does not match type bit(10)
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("bit string length 8 does not match type bit(10)",,,22026)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
@@ -766,9 +766,9 @@ SELECT pg_input_is_valid('01010Z01', 'bit(8)');
 (1 row)
 
 SELECT pg_input_error_message('01010Z01', 'bit(8)');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+            pg_input_error_message             
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
@@ -778,9 +778,9 @@ SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
 (1 row)
 
 SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+               pg_input_error_message               
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
@@ -790,9 +790,9 @@ SELECT pg_input_is_valid('01010Z01', 'varbit');
 (1 row)
 
 SELECT pg_input_error_message('01010Z01', 'varbit');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+            pg_input_error_message             
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
@@ -802,8 +802,8 @@ SELECT pg_input_is_valid('x01010Z01', 'varbit');
 (1 row)
 
 SELECT pg_input_error_message('x01010Z01', 'varbit');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+               pg_input_error_message               
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/boolean.out b/src/test/regress/expected/boolean.out
index 977124b20b..331a8d2890 100644
--- a/src/test/regress/expected/boolean.out
+++ b/src/test/regress/expected/boolean.out
@@ -156,9 +156,9 @@ SELECT pg_input_is_valid('asdf', 'bool');
 (1 row)
 
 SELECT pg_input_error_message('junk', 'bool');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type boolean: "junk"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type boolean: ""junk""",,,22P02)
 (1 row)
 
 -- and, or, not in qualifications
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 0d70194def..7e7cbfee9c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -647,9 +647,9 @@ SELECT pg_input_is_valid('200', 'box');
 (1 row)
 
 SELECT pg_input_error_message('200', 'box');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type box: "200"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type box: ""200""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
@@ -659,8 +659,8 @@ SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
 (1 row)
 
 SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-                   pg_input_error_message                    
--------------------------------------------------------------
- invalid input syntax for type box: "((200,300),(500, xyz))"
+                          pg_input_error_message                           
+---------------------------------------------------------------------------
+ ("invalid input syntax for type box: ""((200,300),(500, xyz))""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/char_1.out b/src/test/regress/expected/char_1.out
index 3dcb0daa0d..32e4b28f6c 100644
--- a/src/test/regress/expected/char_1.out
+++ b/src/test/regress/expected/char_1.out
@@ -133,9 +133,9 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+              pg_input_error_message              
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index c0dec448e1..d3fca737eb 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -860,15 +860,15 @@ SELECT pg_input_is_valid('6874898-01-01', 'date');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'date');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type date: "garbage"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type date: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('6874898-01-01', 'date');
-       pg_input_error_message       
-------------------------------------
- date out of range: "6874898-01-01"
+              pg_input_error_message              
+--------------------------------------------------
+ ("date out of range: ""6874898-01-01""",,,22008)
 (1 row)
 
 RESET datestyle;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 25f6bb9e1f..c4adce88c1 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -109,27 +109,27 @@ select pg_input_is_valid('-1', 'positiveint');
 (1 row)
 
 select pg_input_error_message('junk', 'positiveint');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type integer: "junk"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type integer: ""junk""",,,22P02)
 (1 row)
 
 select pg_input_error_message('-1', 'positiveint');
-                           pg_input_error_message                           
-----------------------------------------------------------------------------
- value for domain positiveint violates check constraint "positiveint_check"
+                                  pg_input_error_message                                  
+------------------------------------------------------------------------------------------
+ ("value for domain positiveint violates check constraint ""positiveint_check""",,,23514)
 (1 row)
 
 select pg_input_error_message('junk', 'weirdfloat');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type double precision: "junk"
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""junk""",,,22P02)
 (1 row)
 
 select pg_input_error_message('0.01', 'weirdfloat');
-                          pg_input_error_message                          
---------------------------------------------------------------------------
- value for domain weirdfloat violates check constraint "weirdfloat_check"
+                                 pg_input_error_message                                 
+----------------------------------------------------------------------------------------
+ ("value for domain weirdfloat violates check constraint ""weirdfloat_check""",,,23514)
 (1 row)
 
 -- We currently can't trap errors raised in the CHECK expression itself
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4b45fcf8f0..c3cf9625b4 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -38,15 +38,15 @@ SELECT pg_input_is_valid('mauve', 'rainbow');
 (1 row)
 
 SELECT pg_input_error_message('mauve', 'rainbow');
-            pg_input_error_message             
------------------------------------------------
- invalid input value for enum rainbow: "mauve"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""mauve""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
-                                                                                                                                          pg_input_error_message                                                                                                                                          
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
+                                                                                                                                                 pg_input_error_message                                                                                                                                                 
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 1d7090a90d..7b0f71a23d 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -101,9 +101,9 @@ SELECT pg_input_is_valid('1e400', 'float4');
 (1 row)
 
 SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+               pg_input_error_message                
+-----------------------------------------------------
+ ("""1e400"" is out of range for type real",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 2b25784f7f..f6c8941438 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -88,9 +88,9 @@ SELECT pg_input_is_valid('1e4000', 'float8');
 (1 row)
 
 SELECT pg_input_error_message('1e4000', 'float8');
-               pg_input_error_message               
-----------------------------------------------------
- "1e4000" is out of range for type double precision
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("""1e4000"" is out of range for type double precision",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 291cacdf4f..54bc17a6d7 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5303,9 +5303,9 @@ SELECT pg_input_is_valid('(1', 'circle');
 (1 row)
 
 SELECT pg_input_error_message('1,', 'circle');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type circle: "1,"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type circle: ""1,""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
@@ -5315,8 +5315,8 @@ SELECT pg_input_is_valid('(1,2),-1', 'circle');
 (1 row)
 
 SELECT pg_input_error_message('(1,2),-1', 'circle');
-              pg_input_error_message              
---------------------------------------------------
- invalid input syntax for type circle: "(1,2),-1"
+                     pg_input_error_message                     
+----------------------------------------------------------------
+ ("invalid input syntax for type circle: ""(1,2),-1""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index c9f466ac1d..957c0003fc 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1064,9 +1064,9 @@ SELECT pg_input_is_valid('1234', 'cidr');
 (1 row)
 
 SELECT pg_input_error_message('1234', 'cidr');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type cidr: "1234"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type cidr: ""1234""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
@@ -1076,9 +1076,9 @@ SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
 (1 row)
 
 SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
-          pg_input_error_message          
-------------------------------------------
- invalid cidr value: "192.168.198.200/24"
+                                    pg_input_error_message                                    
+----------------------------------------------------------------------------------------------
+ ("invalid cidr value: ""192.168.198.200/24""","Value has bits set to right of mask.",,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('1234', 'inet');
@@ -1088,8 +1088,8 @@ SELECT pg_input_is_valid('1234', 'inet');
 (1 row)
 
 SELECT pg_input_error_message('1234', 'inet');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type inet: "1234"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type inet: ""1234""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 73b4ee023c..d42b15c423 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -65,9 +65,9 @@ SELECT pg_input_is_valid('50000', 'int2');
 (1 row)
 
 SELECT pg_input_error_message('50000', 'int2');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 -- While we're here, check int2vector as well
@@ -78,15 +78,15 @@ SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
 (1 row)
 
 SELECT pg_input_error_message('1 asdf', 'int2vector');
-             pg_input_error_message             
-------------------------------------------------
- invalid input syntax for type smallint: "asdf"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("invalid input syntax for type smallint: ""asdf""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('50000', 'int2vector');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 SELECT * FROM INT2_TBL AS f(a, b);
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 9c20574ca5..683415a948 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -65,9 +65,9 @@ SELECT pg_input_is_valid('1000000000000', 'int4');
 (1 row)
 
 SELECT pg_input_error_message('1000000000000', 'int4');
-                 pg_input_error_message                 
---------------------------------------------------------
- value "1000000000000" is out of range for type integer
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("value ""1000000000000"" is out of range for type integer",,,22003)
 (1 row)
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index d9dca64e88..e081cb6b00 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -62,9 +62,9 @@ SELECT pg_input_is_valid('10000000000000000000', 'int8');
 (1 row)
 
 SELECT pg_input_error_message('10000000000000000000', 'int8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "10000000000000000000" is out of range for type bigint
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""10000000000000000000"" is out of range for type bigint",,,22003)
 (1 row)
 
 -- int8/int8 cmp
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a154840c85..2a7b49c36c 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -92,15 +92,15 @@ SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'interval');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type interval: "garbage"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type interval: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('@ 30 eons ago', 'interval');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type interval: "@ 30 eons ago"
+                        pg_input_error_message                         
+-----------------------------------------------------------------------
+ ("invalid input syntax for type interval: ""@ 30 eons ago""",,,22007)
 (1 row)
 
 -- test interval operators
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index af96ce4180..a3096c2c2e 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -334,9 +334,9 @@ select pg_input_is_valid('{"a":true', 'json');
 (1 row)
 
 select pg_input_error_message('{"a":true', 'json');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+                                pg_input_error_message                                
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
 --constructors
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
index 083621fb21..54a5bb75f5 100644
--- a/src/test/regress/expected/json_encoding.out
+++ b/src/test/regress/expected/json_encoding.out
@@ -264,6 +264,6 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
  pg_input_error_message 
 ------------------------
- 
+ (,,,)
 (1 row)
 
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index d3248aa0fd..dc125b1b56 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -324,15 +324,15 @@ select pg_input_is_valid('{"a":true', 'jsonb');
 (1 row)
 
 select pg_input_error_message('{"a":true', 'jsonb');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+                                pg_input_error_message                                
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
 select pg_input_error_message('{"a":1e1000000}', 'jsonb');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+           pg_input_error_message           
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 -- make sure jsonb is passed through json generators without being escaped
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index ca0cdf1ab2..87a4141f3a 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -1041,12 +1041,12 @@ FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '@ + 1',
                   '00',
                   '1a']) str;
-                 jsonpath                  | ok |                                errmsg                                 
--------------------------------------------+----+-----------------------------------------------------------------------
- $ ? (@ like_regex "pattern" flag "smixq") | t  | 
- $ ? (@ like_regex "pattern" flag "a")     | f  | invalid input syntax for type jsonpath
- @ + 1                                     | f  | @ is not allowed in root expressions
- 00                                        | f  | trailing junk after numeric literal at or near "00" of jsonpath input
- 1a                                        | f  | trailing junk after numeric literal at or near "1a" of jsonpath input
+                 jsonpath                  | ok |                                                     errmsg                                                     
+-------------------------------------------+----+----------------------------------------------------------------------------------------------------------------
+ $ ? (@ like_regex "pattern" flag "smixq") | t  | (,,,)
+ $ ? (@ like_regex "pattern" flag "a")     | f  | ("invalid input syntax for type jsonpath","Unrecognized flag character ""a"" in LIKE_REGEX predicate.",,42601)
+ @ + 1                                     | f  | ("@ is not allowed in root expressions",,,42601)
+ 00                                        | f  | ("trailing junk after numeric literal at or near ""00"" of jsonpath input",,,42601)
+ 1a                                        | f  | ("trailing junk after numeric literal at or near ""1a"" of jsonpath input",,,42601)
 (5 rows)
 
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index 6baea8fdbd..4f67aee728 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -93,9 +93,9 @@ SELECT pg_input_is_valid('{1, 1}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1}', 'line');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type line: "{1, 1}"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
@@ -105,9 +105,9 @@ SELECT pg_input_is_valid('{0, 0, 0}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{0, 0, 0}', 'line');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid line specification: A and B cannot both be zero
+                       pg_input_error_message                        
+---------------------------------------------------------------------
+ ("invalid line specification: A and B cannot both be zero",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
@@ -117,9 +117,9 @@ SELECT pg_input_is_valid('{1, 1, a}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1, a}', 'line');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type line: "{1, 1, a}"
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1, a}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
@@ -129,9 +129,9 @@ SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
@@ -141,8 +141,8 @@ SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
 (1 row)
 
 SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index afb323fe04..14e4f73ed1 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -50,8 +50,8 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type lseg: "[(1,2),(3)]"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type lseg: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index cb646af79b..ca7c5f71ef 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -166,9 +166,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
-                   pg_input_error_message                   
-------------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+                          pg_input_error_message                          
+--------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
@@ -178,8 +178,8 @@ SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index bf681988f8..fa5308bb1f 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -360,9 +360,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+                             pg_input_error_message                              
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
@@ -372,8 +372,8 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 46b2eab51a..574cbd17a5 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -339,9 +339,9 @@ SELECT pg_input_is_valid('\x0001', 'money');
 (1 row)
 
 SELECT pg_input_error_message('\x0001', 'money');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type money: "\x0001"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("invalid input syntax for type money: ""\\x0001""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
@@ -351,9 +351,9 @@ SELECT pg_input_is_valid('192233720368547758.07', 'money');
 (1 row)
 
 SELECT pg_input_error_message('192233720368547758.07', 'money');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "192233720368547758.07" is out of range for type money
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""192233720368547758.07"" is out of range for type money",,,22003)
 (1 row)
 
 -- documented minimums and maximums
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index e70896b754..79137d14bb 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -288,9 +288,9 @@ select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
 (1 row)
 
 select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
-            pg_input_error_message             
------------------------------------------------
- malformed multirange literal: "{[1,2], [4,5]"
+                                pg_input_error_message                                 
+---------------------------------------------------------------------------------------
+ ("malformed multirange literal: ""{[1,2], [4,5]""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
@@ -300,9 +300,9 @@ select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
 (1 row)
 
 select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 56a3f3630a..cee8603dad 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2313,9 +2313,9 @@ SELECT pg_input_is_valid('1e400000', 'numeric');
 (1 row)
 
 SELECT pg_input_error_message('1e400000', 'numeric');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+           pg_input_error_message           
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
@@ -2331,15 +2331,15 @@ SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
 (1 row)
 
 SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
- pg_input_error_message 
-------------------------
- numeric field overflow
+                                                pg_input_error_message                                                 
+-----------------------------------------------------------------------------------------------------------------------
+ ("numeric field overflow","A field with precision 7, scale 4 must round to an absolute value less than 10^3.",,22003)
 (1 row)
 
 SELECT pg_input_error_message('0x1234.567', 'numeric');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type numeric: "0x1234.567"
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("invalid input syntax for type numeric: ""0x1234.567""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/oid.out b/src/test/regress/expected/oid.out
index b664bab5f9..2a4c3b08df 100644
--- a/src/test/regress/expected/oid.out
+++ b/src/test/regress/expected/oid.out
@@ -79,9 +79,9 @@ SELECT pg_input_is_valid('01XYZ', 'oid');
 (1 row)
 
 SELECT pg_input_error_message('01XYZ', 'oid');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type oid: "01XYZ"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type oid: ""01XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('9999999999', 'oid');
@@ -91,9 +91,9 @@ SELECT pg_input_is_valid('9999999999', 'oid');
 (1 row)
 
 SELECT pg_input_error_message('9999999999', 'oid');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 -- While we're here, check oidvector as well
@@ -110,9 +110,9 @@ SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
 (1 row)
 
 SELECT pg_input_error_message('01 01XYZ', 'oidvector');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type oid: "XYZ"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type oid: ""XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
@@ -122,9 +122,9 @@ SELECT pg_input_is_valid('01 9999999999', 'oidvector');
 (1 row)
 
 SELECT pg_input_error_message('01 9999999999', 'oidvector');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 529a5e6fc2..2886091675 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -88,9 +88,9 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2),(3)]', 'path');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type path: "[(1,2),(3)]"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
@@ -100,8 +100,8 @@ SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type path: "[(1,2,6),(3,4,6)]"
+                        pg_input_error_message                         
+-----------------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2,6),(3,4,6)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out
index 01501f8c9b..7dfa0bae8b 100644
--- a/src/test/regress/expected/pg_lsn.out
+++ b/src/test/regress/expected/pg_lsn.out
@@ -34,9 +34,9 @@ SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
 (1 row)
 
 SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type pg_lsn: "16AE7F7"
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("invalid input syntax for type pg_lsn: ""16AE7F7""",,,22P02)
 (1 row)
 
 -- Min/Max aggregation
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index a716ceb881..5a5b1ac4ef 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -471,8 +471,8 @@ SELECT pg_input_is_valid('1,y', 'point');
 (1 row)
 
 SELECT pg_input_error_message('1,y', 'point');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type point: "1,y"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type point: ""1,y""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index c7d565ad53..ef31e4c631 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -314,9 +314,9 @@ SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
 (1 row)
 
 SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type polygon: "(2.0,0.8,0.1)"
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,0.8,0.1)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
@@ -326,8 +326,8 @@ SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
 (1 row)
 
 SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type polygon: "(2.0,xyz)"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,xyz)""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 95d1e5515f..c2e82f39e7 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2247,9 +2247,9 @@ SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
-     pg_input_error_message      
----------------------------------
- a name must follow the "/" sign
+            pg_input_error_message             
+-----------------------------------------------
+ ("a name must follow the ""/"" sign",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
@@ -2259,9 +2259,9 @@ SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem')
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-           pg_input_error_message           
---------------------------------------------
- role "regress_no_such_user" does not exist
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("role ""regress_no_such_user"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
@@ -2271,9 +2271,9 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid mode character: must be one of ""arwdDxtXUCTcsAm""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a3e9e447af..e3f1029555 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -189,9 +189,9 @@ select pg_input_is_valid('(1,4', 'int4range');
 (1 row)
 
 select pg_input_error_message('(1,4', 'int4range');
-     pg_input_error_message      
----------------------------------
- malformed range literal: "(1,4"
+                         pg_input_error_message                          
+-------------------------------------------------------------------------
+ ("malformed range literal: ""(1,4""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('(4,1)', 'int4range');
@@ -201,9 +201,9 @@ select pg_input_is_valid('(4,1)', 'int4range');
 (1 row)
 
 select pg_input_error_message('(4,1)', 'int4range');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- range lower bound must be less than or equal to range upper bound
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("range lower bound must be less than or equal to range upper bound",,,22000)
 (1 row)
 
 select pg_input_is_valid('(4,zed)', 'int4range');
@@ -213,9 +213,9 @@ select pg_input_is_valid('(4,zed)', 'int4range');
 (1 row)
 
 select pg_input_error_message('(4,zed)', 'int4range');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('[1,2147483647]', 'int4range');
@@ -225,9 +225,9 @@ select pg_input_is_valid('[1,2147483647]', 'int4range');
 (1 row)
 
 select pg_input_error_message('[1,2147483647]', 'int4range');
- pg_input_error_message 
-------------------------
- integer out of range
+      pg_input_error_message      
+----------------------------------
+ ("integer out of range",,,22003)
 (1 row)
 
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
@@ -237,9 +237,9 @@ select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
 (1 row)
 
 select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
- pg_input_error_message 
-------------------------
- date out of range
+    pg_input_error_message     
+-------------------------------
+ ("date out of range",,,22008)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..cd1d79bad7 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -449,9 +449,9 @@ SELECT to_regnamespace('foo.bar');
 
 -- Test soft-error API
 SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
-            pg_input_error_message             
------------------------------------------------
- relation "ng_catalog.pg_class" does not exist
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("relation ""ng_catalog.pg_class"" does not exist",,,42P01)
 (1 row)
 
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
@@ -461,75 +461,75 @@ SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
 (1 row)
 
 SELECT pg_input_error_message('no_such_config', 'regconfig');
-                  pg_input_error_message                   
------------------------------------------------------------
- text search configuration "no_such_config" does not exist
+                         pg_input_error_message                          
+-------------------------------------------------------------------------
+ ("text search configuration ""no_such_config"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-                   pg_input_error_message                   
-------------------------------------------------------------
- text search dictionary "no_such_dictionary" does not exist
+                          pg_input_error_message                          
+--------------------------------------------------------------------------
+ ("text search dictionary ""no_such_dictionary"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-       pg_input_error_message        
--------------------------------------
- schema "nonexistent" does not exist
+              pg_input_error_message               
+---------------------------------------------------
+ ("schema ""nonexistent"" does not exist",,,3F000)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-         pg_input_error_message          
------------------------------------------
- operator does not exist: ng_catalog.||/
+               pg_input_error_message                
+-----------------------------------------------------
+ ("operator does not exist: ng_catalog.||/",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('-', 'regoper');
-     pg_input_error_message     
---------------------------------
- more than one operator named -
+           pg_input_error_message           
+--------------------------------------------
+ ("more than one operator named -",,,42725)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-              pg_input_error_message              
---------------------------------------------------
- operator does not exist: ng_catalog.+(int4,int4)
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("operator does not exist: ng_catalog.+(int4,int4)",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('-', 'regoperator');
-   pg_input_error_message    
------------------------------
- expected a left parenthesis
+         pg_input_error_message          
+-----------------------------------------
+ ("expected a left parenthesis",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-          pg_input_error_message          
-------------------------------------------
- function "ng_catalog.now" does not exist
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("function ""ng_catalog.now"" does not exist",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-              pg_input_error_message               
----------------------------------------------------
- function "ng_catalog.abs(numeric)" does not exist
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("function ""ng_catalog.abs(numeric)"" does not exist",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-    pg_input_error_message    
-------------------------------
- expected a right parenthesis
+          pg_input_error_message          
+------------------------------------------
+ ("expected a right parenthesis",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-           pg_input_error_message           
---------------------------------------------
- role "regress_regrole_test" does not exist
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("role ""regress_regrole_test"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('no_such_type', 'regtype');
-       pg_input_error_message       
-------------------------------------
- type "no_such_type" does not exist
+              pg_input_error_message              
+--------------------------------------------------
+ ("type ""no_such_type"" does not exist",,,42704)
 (1 row)
 
 -- Some cases that should be soft errors, but are not yet
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 801d9e556b..a9fb5320e3 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -89,15 +89,15 @@ SELECT pg_input_is_valid('(1,zed)', 'complex');
 (1 row)
 
 SELECT pg_input_error_message('(1,zed)', 'complex');
-                pg_input_error_message                 
--------------------------------------------------------
- invalid input syntax for type double precision: "zed"
+                       pg_input_error_message                        
+---------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""zed""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('(1,1e400)', 'complex');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 create temp table quadtable(f1 int, q quad);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index f028c1f10f..28c78c960b 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -281,21 +281,21 @@ SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
 (1 row)
 
 SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-             pg_input_error_message             
-------------------------------------------------
- invalid hexadecimal data: odd number of digits
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid hexadecimal data: odd number of digits",,,22023)
 (1 row)
 
 SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-     pg_input_error_message     
---------------------------------
- invalid hexadecimal digit: "x"
+            pg_input_error_message            
+----------------------------------------------
+ ("invalid hexadecimal digit: ""x""",,,22023)
 (1 row)
 
 SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
-       pg_input_error_message        
--------------------------------------
- invalid input syntax for type bytea
+             pg_input_error_message              
+-------------------------------------------------
+ ("invalid input syntax for type bytea",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out
index ff67ed43f0..7ee891cc1a 100644
--- a/src/test/regress/expected/tid.out
+++ b/src/test/regress/expected/tid.out
@@ -25,9 +25,9 @@ SELECT pg_input_is_valid('(0)', 'tid');
 (1 row)
 
 SELECT pg_input_error_message('(0)', 'tid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type tid: "(0)"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(0,-1)', 'tid');
@@ -37,9 +37,9 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
 (1 row)
 
 SELECT pg_input_error_message('(0,-1)', 'tid');
-           pg_input_error_message            
----------------------------------------------
- invalid input syntax for type tid: "(0,-1)"
+                  pg_input_error_message                   
+-----------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0,-1)""",,,22P02)
 (1 row)
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index a44caededd..79de9377db 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -134,15 +134,15 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
 (1 row)
 
 SELECT pg_input_error_message('25:00:00', 'time');
-             pg_input_error_message             
-------------------------------------------------
- date/time field value out of range: "25:00:00"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00""",,,22008)
 (1 row)
 
 SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type time: "15:36:39 America/New_York"
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type time: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index eef2f7001c..eafccc38ac 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -145,15 +145,15 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'timestamp');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type timestamp: "garbage"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("invalid input syntax for type timestamp: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index b85a93a3c2..73c7d70455 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -196,15 +196,15 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'timestamptz');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type timestamp with time zone: "garbage"
+                             pg_input_error_message                              
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type timestamp with time zone: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 984285663b..665fa4495c 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -151,15 +151,15 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
 (1 row)
 
 SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-               pg_input_error_message               
-----------------------------------------------------
- date/time field value out of range: "25:00:00 PDT"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00 PDT""",,,22008)
 (1 row)
 
 SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
-                             pg_input_error_message                             
---------------------------------------------------------------------------------
- invalid input syntax for type time with time zone: "15:36:39 America/New_York"
+                                    pg_input_error_message                                    
+----------------------------------------------------------------------------------------------
+ ("invalid input syntax for type time with time zone: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index a8785cd708..35b19814c4 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -103,9 +103,9 @@ SELECT pg_input_is_valid($$''$$, 'tsvector');
 (1 row)
 
 SELECT pg_input_error_message($$''$$, 'tsvector');
-     pg_input_error_message     
---------------------------------
- syntax error in tsvector: "''"
+            pg_input_error_message            
+----------------------------------------------
+ ("syntax error in tsvector: ""''""",,,42601)
 (1 row)
 
 --Base tsquery test
@@ -405,15 +405,15 @@ SELECT pg_input_is_valid('foo!', 'tsquery');
 (1 row)
 
 SELECT pg_input_error_message('foo!', 'tsquery');
-     pg_input_error_message      
----------------------------------
- syntax error in tsquery: "foo!"
+            pg_input_error_message             
+-----------------------------------------------
+ ("syntax error in tsquery: ""foo!""",,,42601)
 (1 row)
 
 SELECT pg_input_error_message('a <100000> b', 'tsquery');
-                                pg_input_error_message                                 
----------------------------------------------------------------------------------------
- distance in phrase operator must be an integer value between zero and 16384 inclusive
+                                      pg_input_error_message                                       
+---------------------------------------------------------------------------------------------------
+ ("distance in phrase operator must be an integer value between zero and 16384 inclusive",,,22023)
 (1 row)
 
 --comparisons
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 0f47232009..3934626dda 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -47,9 +47,9 @@ SELECT pg_input_is_valid('11', 'uuid');
 (1 row)
 
 SELECT pg_input_error_message('11', 'uuid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type uuid: "11"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type uuid: ""11""",,,22P02)
 (1 row)
 
 --inserting three input formats
diff --git a/src/test/regress/expected/varchar_1.out b/src/test/regress/expected/varchar_1.out
index 6690f81c0b..ee0e920e84 100644
--- a/src/test/regress/expected/varchar_1.out
+++ b/src/test/regress/expected/varchar_1.out
@@ -125,8 +125,8 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index e62f701943..754ff6b725 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -44,9 +44,9 @@ SELECT pg_input_is_valid('asdf', 'xid');
 (1 row)
 
 SELECT pg_input_error_message('0xffffffffff', 'xid');
-              pg_input_error_message               
----------------------------------------------------
- value "0xffffffffff" is out of range for type xid
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("value ""0xffffffffff"" is out of range for type xid",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('42', 'xid8');
@@ -62,9 +62,9 @@ SELECT pg_input_is_valid('asdf', 'xid8');
 (1 row)
 
 SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "0xffffffffffffffffffff" is out of range for type xid8
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""0xffffffffffffffffffff"" is out of range for type xid8",,,22003)
 (1 row)
 
 -- equality
@@ -224,9 +224,9 @@ select pg_input_is_valid('31:12:', 'pg_snapshot');
 (1 row)
 
 select pg_input_error_message('31:12:', 'pg_snapshot');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type pg_snapshot: "31:12:"
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""31:12:""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
@@ -236,9 +236,9 @@ select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
 (1 row)
 
 select pg_input_error_message('12:16:14,13', 'pg_snapshot');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type pg_snapshot: "12:16:14,13"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""12:16:14,13""",,,22P02)
 (1 row)
 
 create temp table snapshot_test (
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..e1a8f09a42 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -32,9 +32,17 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
 (1 row)
 
 SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
-------------------------
- invalid XML content
+                        pg_input_error_message                         
+-----------------------------------------------------------------------
+ ("invalid XML content","line 1: expected '>'                         +
+ <value>one</                                                         +
+             ^                                                        +
+ line 1: Opening and ending tag mismatch: value line 1 and unparseable+
+ <value>one</                                                         +
+             ^                                                        +
+ line 1: chunk is not well balanced                                   +
+ <value>one</                                                         +
+             ^",,2200N)
 (1 row)
 
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
@@ -44,9 +52,9 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 (1 row)
 
 SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
-----------------------------------------------
- invalid XML content: invalid XML declaration
+                                      pg_input_error_message                                      
+--------------------------------------------------------------------------------------------------
+ ("invalid XML content: invalid XML declaration","standalone accepts only 'yes' or 'no'.",,2200N)
 (1 row)
 
 SELECT xmlcomment('test');
-- 
2.25.1

#6Nathan Bossart
nathandbossart@gmail.com
In reply to: Nathan Bossart (#5)
Re: verbose mode for pg_input_error_message?

On Thu, Feb 23, 2023 at 10:40:48AM -0800, Nathan Bossart wrote:

On Tue, Jan 10, 2023 at 03:41:12PM -0800, Nathan Bossart wrote:

My vote would be to redefine the existing pg_input_error_message() function
to return a record, but I recognize that this would inflate the patch quite
a bit due to all the existing uses in the tests. If this is the only
argument against this approach, I'm happy to help with the patch.

Here's an attempt at this.

This seems to have made cfbot angry. Will post a new version shortly.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

#7Nathan Bossart
nathandbossart@gmail.com
In reply to: Nathan Bossart (#6)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On Thu, Feb 23, 2023 at 11:30:38AM -0800, Nathan Bossart wrote:

Will post a new version shortly.

As promised...

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

Attachments:

v3-0001-add-details-to-pg_input_error_message.patchtext/x-diff; charset=us-asciiDownload
From b284ba24f771b6ccbf599839bdc813af718b91a1 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Thu, 23 Feb 2023 10:31:24 -0800
Subject: [PATCH v3 1/1] add details to pg_input_error_message

---
 contrib/cube/expected/cube.out                |  6 +-
 contrib/hstore/expected/hstore.out            | 12 +--
 contrib/intarray/expected/_int.out            | 10 +--
 contrib/isn/expected/isn.out                  | 10 +--
 contrib/ltree/expected/ltree.out              | 20 ++---
 contrib/seg/expected/seg.out                  | 16 ++--
 doc/src/sgml/func.sgml                        | 29 ++++---
 src/backend/utils/adt/misc.c                  | 38 +++++++--
 src/include/catalog/pg_proc.dat               | 10 ++-
 src/test/regress/expected/arrays.out          |  6 +-
 src/test/regress/expected/bit.out             | 30 +++----
 src/test/regress/expected/boolean.out         |  6 +-
 src/test/regress/expected/box.out             | 12 +--
 src/test/regress/expected/char.out            |  6 +-
 src/test/regress/expected/char_1.out          |  6 +-
 src/test/regress/expected/char_2.out          |  6 +-
 src/test/regress/expected/date.out            | 12 +--
 src/test/regress/expected/domain.out          | 24 +++---
 src/test/regress/expected/enum.out            | 12 +--
 src/test/regress/expected/float4.out          |  6 +-
 src/test/regress/expected/float8.out          |  6 +-
 src/test/regress/expected/geometry.out        | 12 +--
 src/test/regress/expected/inet.out            | 18 ++---
 src/test/regress/expected/int2.out            | 18 ++---
 src/test/regress/expected/int4.out            |  6 +-
 src/test/regress/expected/int8.out            |  6 +-
 src/test/regress/expected/interval.out        | 12 +--
 src/test/regress/expected/json.out            |  6 +-
 src/test/regress/expected/json_encoding.out   |  2 +-
 src/test/regress/expected/json_encoding_1.out |  6 +-
 src/test/regress/expected/jsonb.out           | 12 +--
 src/test/regress/expected/jsonpath.out        | 14 ++--
 src/test/regress/expected/line.out            | 30 +++----
 src/test/regress/expected/lseg.out            |  6 +-
 src/test/regress/expected/macaddr.out         | 12 +--
 src/test/regress/expected/macaddr8.out        | 12 +--
 src/test/regress/expected/money.out           | 12 +--
 src/test/regress/expected/multirangetypes.out | 12 +--
 src/test/regress/expected/numeric.out         | 18 ++---
 src/test/regress/expected/oid.out             | 24 +++---
 src/test/regress/expected/path.out            | 12 +--
 src/test/regress/expected/pg_lsn.out          |  6 +-
 src/test/regress/expected/point.out           |  6 +-
 src/test/regress/expected/polygon.out         | 12 +--
 src/test/regress/expected/privileges.out      | 18 ++---
 src/test/regress/expected/rangetypes.out      | 30 +++----
 src/test/regress/expected/regproc.out         | 78 +++++++++----------
 src/test/regress/expected/rowtypes.out        | 12 +--
 src/test/regress/expected/strings.out         | 18 ++---
 src/test/regress/expected/tid.out             | 12 +--
 src/test/regress/expected/time.out            | 12 +--
 src/test/regress/expected/timestamp.out       | 12 +--
 src/test/regress/expected/timestamptz.out     | 12 +--
 src/test/regress/expected/timetz.out          | 12 +--
 src/test/regress/expected/tstypes.out         | 18 ++---
 src/test/regress/expected/uuid.out            |  6 +-
 src/test/regress/expected/varchar.out         |  6 +-
 src/test/regress/expected/varchar_1.out       |  6 +-
 src/test/regress/expected/varchar_2.out       |  6 +-
 src/test/regress/expected/xid.out             | 24 +++---
 src/test/regress/expected/xml.out             | 10 +--
 src/test/regress/expected/xml_1.out           |  4 +-
 src/test/regress/expected/xml_2.out           |  8 +-
 src/test/regress/sql/xml.sql                  |  4 +-
 64 files changed, 452 insertions(+), 413 deletions(-)

diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index dc23e5ccc0..3bb42b063b 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -345,9 +345,9 @@ SELECT pg_input_is_valid('-1e-700', 'cube');
 (1 row)
 
 SELECT pg_input_error_message('-1e-700', 'cube');
-               pg_input_error_message                
------------------------------------------------------
- "-1e-700" is out of range for type double precision
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("""-1e-700"" is out of range for type double precision",,,22003)
 (1 row)
 
 --
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index d6faa91867..d58fee585e 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -266,15 +266,15 @@ select pg_input_is_valid('a=b', 'hstore');
 (1 row)
 
 select pg_input_error_message('a=b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "b" at position 2
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""b"" at position 2",,,42601)
 (1 row)
 
 select pg_input_error_message(' =>b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "=" at position 1
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""="" at position 1",,,42601)
 (1 row)
 
 -- -> operator
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index c953065a5c..73dfea605a 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -406,11 +406,11 @@ FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
       AS a(str);
-    query_int    | ok |    errmsg    
------------------+----+--------------
- 1&(2&(4&(5|6))) | t  | 
- 1#(2&(4&(5&6))) | f  | syntax error
- foo             | f  | syntax error
+    query_int    | ok |          errmsg          
+-----------------+----+--------------------------
+ 1&(2&(4&(5|6))) | t  | (,,,)
+ 1#(2&(4&(5&6))) | f  | ("syntax error",,,42601)
+ foo             | f  | ("syntax error",,,42601)
 (3 rows)
 
 CREATE TABLE test__int( a int[] );
diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out
index 72171b2790..cbe4166fd0 100644
--- a/contrib/isn/expected/isn.out
+++ b/contrib/isn/expected/isn.out
@@ -268,11 +268,11 @@ FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
       AS a(str,typ);
-      isn      | type  | ok |                         errmsg                         
----------------+-------+----+--------------------------------------------------------
- 9780123456786 | UPC   | f  | cannot cast ISBN to UPC for number: "9780123456786"
- postgresql... | EAN13 | f  | invalid input syntax for EAN13 number: "postgresql..."
- 9771234567003 | ISSN  | t  | 
+      isn      | type  | ok |                                errmsg                                
+---------------+-------+----+----------------------------------------------------------------------
+ 9780123456786 | UPC   | f  | ("cannot cast ISBN to UPC for number: ""9780123456786""",,,22P02)
+ postgresql... | EAN13 | f  | ("invalid input syntax for EAN13 number: ""postgresql...""",,,22P02)
+ 9771234567003 | ISSN  | t  | (,,,)
 (3 rows)
 
 --
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index d2a53b9f0c..cf925b2469 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -8111,15 +8111,15 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
       AS a(str,typ);
-     value      |   type    | ok |               errmsg               
-----------------+-----------+----+------------------------------------
- .2.3           | ltree     | f  | ltree syntax error at character 1
- 1.2.           | ltree     | f  | ltree syntax error
- 1.2.3          | ltree     | t  | 
- @.2.3          | lquery    | f  | lquery syntax error at character 1
-  2.3           | lquery    | f  | lquery syntax error at character 1
- 1.2.3          | lquery    | t  | 
- $tree & aWdf@* | ltxtquery | f  | operand syntax error
- !tree & aWdf@* | ltxtquery | t  | 
+     value      |   type    | ok |                          errmsg                          
+----------------+-----------+----+----------------------------------------------------------
+ .2.3           | ltree     | f  | ("ltree syntax error at character 1",,,42601)
+ 1.2.           | ltree     | f  | ("ltree syntax error","Unexpected end of input.",,42601)
+ 1.2.3          | ltree     | t  | (,,,)
+ @.2.3          | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+  2.3           | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+ 1.2.3          | lquery    | t  | (,,,)
+ $tree & aWdf@* | ltxtquery | f  | ("operand syntax error",,,42601)
+ !tree & aWdf@* | ltxtquery | t  | (,,,)
 (8 rows)
 
diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 7a06113ed8..4b09bd1d4f 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1283,13 +1283,13 @@ FROM unnest(ARRAY['-1 .. 1'::text,
                   'ABC',
                   '1 e7',
                   '1e700']) str;
-   seg    | ok |                errmsg                 
-----------+----+---------------------------------------
- -1 .. 1  | t  | 
- 100(+-)1 | t  | 
-          | f  | bad seg representation
- ABC      | f  | bad seg representation
- 1 e7     | f  | bad seg representation
- 1e700    | f  | "1e700" is out of range for type real
+   seg    | ok |                              errmsg                               
+----------+----+-------------------------------------------------------------------
+ -1 .. 1  | t  | (,,,)
+ 100(+-)1 | t  | (,,,)
+          | f  | ("bad seg representation","syntax error at end of input",,42601)
+ ABC      | f  | ("bad seg representation","syntax error at or near ""A""",,42601)
+ 1 e7     | f  | ("bad seg representation","syntax error at or near ""e""",,42601)
+ 1e700    | f  | ("""1e700"" is out of range for type real",,,22003)
 (6 rows)
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0cbdf63632..76dade49db 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24781,13 +24781,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
           <parameter>string</parameter> <type>text</type>,
           <parameter>type</parameter> <type>text</type>
         )
-        <returnvalue>text</returnvalue>
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
        </para>
        <para>
         Tests whether the given <parameter>string</parameter> is valid
-        input for the specified data type; if not, return the error
-        message that would have been thrown.  If the input is valid, the
-        result is NULL.  The inputs are the same as
+        input for the specified data type; if not, return the details of
+        the error would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
         for <function>pg_input_is_valid</function>.
        </para>
        <para>
@@ -24798,12 +24802,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
         directly.
         </para>
         <para>
-         <literal>pg_input_error_message('42000000000', 'integer')</literal>
-         <returnvalue>value "42000000000" is out of range for type integer</returnvalue>
-        </para>
-        <para>
-         <literal>pg_input_error_message('1234.567', 'numeric(7,4)')</literal>
-         <returnvalue>numeric field overflow</returnvalue>
+<programlisting>
+SELECT * FROM pg_input_error_message('42000000000', 'integer');
+                       message                        | detail | hint | sql_error_code
+------------------------------------------------------+--------+------+----------------
+ value "42000000000" is out of range for type integer |        |      | 22003
+
+SELECT * FROM pg_input_error_message('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
+</programlisting>
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index f95256efd3..a4f4b7fb90 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -662,7 +662,8 @@ pg_input_is_valid(PG_FUNCTION_ARGS)
 /*
  * pg_input_error_message - test whether string is valid input for datatype.
  *
- * Returns NULL if OK, else the primary message string from the error.
+ * Returns NULL if OK, else the primary message, detail message, hint message,
+ * and sql error code from the error.
  *
  * This will only work usefully if the datatype's input function has been
  * updated to return "soft" errors via errsave/ereturn.
@@ -673,19 +674,44 @@ pg_input_error_message(PG_FUNCTION_ARGS)
 	text	   *txt = PG_GETARG_TEXT_PP(0);
 	text	   *typname = PG_GETARG_TEXT_PP(1);
 	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
 	/* Enable details_wanted */
 	escontext.details_wanted = true;
 
 	if (pg_input_is_valid_common(fcinfo, txt, typname,
 								 &escontext))
-		PG_RETURN_NULL();
+		memset(isnull, true, sizeof(isnull));
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
+
+		memset(isnull, false, sizeof(isnull));
+
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
 
-	Assert(escontext.error_occurred);
-	Assert(escontext.error_data != NULL);
-	Assert(escontext.error_data->message != NULL);
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
 
-	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /* Common subroutine for the above */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e2a7642a2b..ecb5df2e53 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7118,9 +7118,13 @@
   proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool',
   proargtypes => 'text text', prosrc => 'pg_input_is_valid' },
 { oid => '8051',
-  descr => 'get error message if string is not valid input for data type',
-  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
-  proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'record',
+  proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_message' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..0e6a50dbca 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -202,9 +202,9 @@ SELECT pg_input_is_valid('{1,zed}', 'integer[]');
 (1 row)
 
 SELECT pg_input_error_message('{1,zed}', 'integer[]');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 -- test mixed slice/scalar subscripting
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 209044713c..1b88327cb6 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -754,9 +754,9 @@ SELECT pg_input_is_valid('01010001', 'bit(10)');
 (1 row)
 
 SELECT pg_input_error_message('01010001', 'bit(10)');
-             pg_input_error_message              
--------------------------------------------------
- bit string length 8 does not match type bit(10)
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("bit string length 8 does not match type bit(10)",,,22026)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
@@ -766,9 +766,9 @@ SELECT pg_input_is_valid('01010Z01', 'bit(8)');
 (1 row)
 
 SELECT pg_input_error_message('01010Z01', 'bit(8)');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+            pg_input_error_message             
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
@@ -778,9 +778,9 @@ SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
 (1 row)
 
 SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+               pg_input_error_message               
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
@@ -790,9 +790,9 @@ SELECT pg_input_is_valid('01010Z01', 'varbit');
 (1 row)
 
 SELECT pg_input_error_message('01010Z01', 'varbit');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+            pg_input_error_message             
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
@@ -802,8 +802,8 @@ SELECT pg_input_is_valid('x01010Z01', 'varbit');
 (1 row)
 
 SELECT pg_input_error_message('x01010Z01', 'varbit');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+               pg_input_error_message               
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/boolean.out b/src/test/regress/expected/boolean.out
index 977124b20b..331a8d2890 100644
--- a/src/test/regress/expected/boolean.out
+++ b/src/test/regress/expected/boolean.out
@@ -156,9 +156,9 @@ SELECT pg_input_is_valid('asdf', 'bool');
 (1 row)
 
 SELECT pg_input_error_message('junk', 'bool');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type boolean: "junk"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type boolean: ""junk""",,,22P02)
 (1 row)
 
 -- and, or, not in qualifications
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 0d70194def..7e7cbfee9c 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -647,9 +647,9 @@ SELECT pg_input_is_valid('200', 'box');
 (1 row)
 
 SELECT pg_input_error_message('200', 'box');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type box: "200"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type box: ""200""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
@@ -659,8 +659,8 @@ SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
 (1 row)
 
 SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-                   pg_input_error_message                    
--------------------------------------------------------------
- invalid input syntax for type box: "((200,300),(500, xyz))"
+                          pg_input_error_message                           
+---------------------------------------------------------------------------
+ ("invalid input syntax for type box: ""((200,300),(500, xyz))""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/char.out b/src/test/regress/expected/char.out
index 199001b2fe..f565ea844f 100644
--- a/src/test/regress/expected/char.out
+++ b/src/test/regress/expected/char.out
@@ -133,9 +133,9 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+              pg_input_error_message              
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_1.out b/src/test/regress/expected/char_1.out
index 3dcb0daa0d..32e4b28f6c 100644
--- a/src/test/regress/expected/char_1.out
+++ b/src/test/regress/expected/char_1.out
@@ -133,9 +133,9 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+              pg_input_error_message              
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_2.out b/src/test/regress/expected/char_2.out
index dd5d34fe8d..c7221f6d44 100644
--- a/src/test/regress/expected/char_2.out
+++ b/src/test/regress/expected/char_2.out
@@ -133,9 +133,9 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+              pg_input_error_message              
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index c0dec448e1..d3fca737eb 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -860,15 +860,15 @@ SELECT pg_input_is_valid('6874898-01-01', 'date');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'date');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type date: "garbage"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type date: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('6874898-01-01', 'date');
-       pg_input_error_message       
-------------------------------------
- date out of range: "6874898-01-01"
+              pg_input_error_message              
+--------------------------------------------------
+ ("date out of range: ""6874898-01-01""",,,22008)
 (1 row)
 
 RESET datestyle;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 25f6bb9e1f..c4adce88c1 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -109,27 +109,27 @@ select pg_input_is_valid('-1', 'positiveint');
 (1 row)
 
 select pg_input_error_message('junk', 'positiveint');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type integer: "junk"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input syntax for type integer: ""junk""",,,22P02)
 (1 row)
 
 select pg_input_error_message('-1', 'positiveint');
-                           pg_input_error_message                           
-----------------------------------------------------------------------------
- value for domain positiveint violates check constraint "positiveint_check"
+                                  pg_input_error_message                                  
+------------------------------------------------------------------------------------------
+ ("value for domain positiveint violates check constraint ""positiveint_check""",,,23514)
 (1 row)
 
 select pg_input_error_message('junk', 'weirdfloat');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type double precision: "junk"
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""junk""",,,22P02)
 (1 row)
 
 select pg_input_error_message('0.01', 'weirdfloat');
-                          pg_input_error_message                          
---------------------------------------------------------------------------
- value for domain weirdfloat violates check constraint "weirdfloat_check"
+                                 pg_input_error_message                                 
+----------------------------------------------------------------------------------------
+ ("value for domain weirdfloat violates check constraint ""weirdfloat_check""",,,23514)
 (1 row)
 
 -- We currently can't trap errors raised in the CHECK expression itself
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4b45fcf8f0..c3cf9625b4 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -38,15 +38,15 @@ SELECT pg_input_is_valid('mauve', 'rainbow');
 (1 row)
 
 SELECT pg_input_error_message('mauve', 'rainbow');
-            pg_input_error_message             
------------------------------------------------
- invalid input value for enum rainbow: "mauve"
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""mauve""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
-                                                                                                                                          pg_input_error_message                                                                                                                                          
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
+                                                                                                                                                 pg_input_error_message                                                                                                                                                 
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 1d7090a90d..7b0f71a23d 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -101,9 +101,9 @@ SELECT pg_input_is_valid('1e400', 'float4');
 (1 row)
 
 SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+               pg_input_error_message                
+-----------------------------------------------------
+ ("""1e400"" is out of range for type real",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 2b25784f7f..f6c8941438 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -88,9 +88,9 @@ SELECT pg_input_is_valid('1e4000', 'float8');
 (1 row)
 
 SELECT pg_input_error_message('1e4000', 'float8');
-               pg_input_error_message               
-----------------------------------------------------
- "1e4000" is out of range for type double precision
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("""1e4000"" is out of range for type double precision",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 291cacdf4f..54bc17a6d7 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5303,9 +5303,9 @@ SELECT pg_input_is_valid('(1', 'circle');
 (1 row)
 
 SELECT pg_input_error_message('1,', 'circle');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type circle: "1,"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type circle: ""1,""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
@@ -5315,8 +5315,8 @@ SELECT pg_input_is_valid('(1,2),-1', 'circle');
 (1 row)
 
 SELECT pg_input_error_message('(1,2),-1', 'circle');
-              pg_input_error_message              
---------------------------------------------------
- invalid input syntax for type circle: "(1,2),-1"
+                     pg_input_error_message                     
+----------------------------------------------------------------
+ ("invalid input syntax for type circle: ""(1,2),-1""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index c9f466ac1d..957c0003fc 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1064,9 +1064,9 @@ SELECT pg_input_is_valid('1234', 'cidr');
 (1 row)
 
 SELECT pg_input_error_message('1234', 'cidr');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type cidr: "1234"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type cidr: ""1234""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
@@ -1076,9 +1076,9 @@ SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
 (1 row)
 
 SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
-          pg_input_error_message          
-------------------------------------------
- invalid cidr value: "192.168.198.200/24"
+                                    pg_input_error_message                                    
+----------------------------------------------------------------------------------------------
+ ("invalid cidr value: ""192.168.198.200/24""","Value has bits set to right of mask.",,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('1234', 'inet');
@@ -1088,8 +1088,8 @@ SELECT pg_input_is_valid('1234', 'inet');
 (1 row)
 
 SELECT pg_input_error_message('1234', 'inet');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type inet: "1234"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type inet: ""1234""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 73b4ee023c..d42b15c423 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -65,9 +65,9 @@ SELECT pg_input_is_valid('50000', 'int2');
 (1 row)
 
 SELECT pg_input_error_message('50000', 'int2');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 -- While we're here, check int2vector as well
@@ -78,15 +78,15 @@ SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
 (1 row)
 
 SELECT pg_input_error_message('1 asdf', 'int2vector');
-             pg_input_error_message             
-------------------------------------------------
- invalid input syntax for type smallint: "asdf"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("invalid input syntax for type smallint: ""asdf""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('50000', 'int2vector');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 SELECT * FROM INT2_TBL AS f(a, b);
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 9c20574ca5..683415a948 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -65,9 +65,9 @@ SELECT pg_input_is_valid('1000000000000', 'int4');
 (1 row)
 
 SELECT pg_input_error_message('1000000000000', 'int4');
-                 pg_input_error_message                 
---------------------------------------------------------
- value "1000000000000" is out of range for type integer
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("value ""1000000000000"" is out of range for type integer",,,22003)
 (1 row)
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index d9dca64e88..e081cb6b00 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -62,9 +62,9 @@ SELECT pg_input_is_valid('10000000000000000000', 'int8');
 (1 row)
 
 SELECT pg_input_error_message('10000000000000000000', 'int8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "10000000000000000000" is out of range for type bigint
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""10000000000000000000"" is out of range for type bigint",,,22003)
 (1 row)
 
 -- int8/int8 cmp
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a154840c85..2a7b49c36c 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -92,15 +92,15 @@ SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'interval');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type interval: "garbage"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type interval: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('@ 30 eons ago', 'interval');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type interval: "@ 30 eons ago"
+                        pg_input_error_message                         
+-----------------------------------------------------------------------
+ ("invalid input syntax for type interval: ""@ 30 eons ago""",,,22007)
 (1 row)
 
 -- test interval operators
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index af96ce4180..a3096c2c2e 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -334,9 +334,9 @@ select pg_input_is_valid('{"a":true', 'json');
 (1 row)
 
 select pg_input_error_message('{"a":true', 'json');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+                                pg_input_error_message                                
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
 --constructors
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
index 083621fb21..54a5bb75f5 100644
--- a/src/test/regress/expected/json_encoding.out
+++ b/src/test/regress/expected/json_encoding.out
@@ -264,6 +264,6 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
  pg_input_error_message 
 ------------------------
- 
+ (,,,)
 (1 row)
 
diff --git a/src/test/regress/expected/json_encoding_1.out b/src/test/regress/expected/json_encoding_1.out
index 021d226f8d..cb1aec0dfa 100644
--- a/src/test/regress/expected/json_encoding_1.out
+++ b/src/test/regress/expected/json_encoding_1.out
@@ -258,8 +258,8 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 
 -- soft error for input-time failure
 select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
-       pg_input_error_message        
--------------------------------------
- unsupported Unicode escape sequence
+                                                      pg_input_error_message                                                       
+-----------------------------------------------------------------------------------------------------------------------------------
+ ("unsupported Unicode escape sequence","Unicode escape value could not be translated to the server's encoding SQL_ASCII.",,22P05)
 (1 row)
 
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index d3248aa0fd..dc125b1b56 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -324,15 +324,15 @@ select pg_input_is_valid('{"a":true', 'jsonb');
 (1 row)
 
 select pg_input_error_message('{"a":true', 'jsonb');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+                                pg_input_error_message                                
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
 select pg_input_error_message('{"a":1e1000000}', 'jsonb');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+           pg_input_error_message           
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 -- make sure jsonb is passed through json generators without being escaped
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index ca0cdf1ab2..87a4141f3a 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -1041,12 +1041,12 @@ FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '@ + 1',
                   '00',
                   '1a']) str;
-                 jsonpath                  | ok |                                errmsg                                 
--------------------------------------------+----+-----------------------------------------------------------------------
- $ ? (@ like_regex "pattern" flag "smixq") | t  | 
- $ ? (@ like_regex "pattern" flag "a")     | f  | invalid input syntax for type jsonpath
- @ + 1                                     | f  | @ is not allowed in root expressions
- 00                                        | f  | trailing junk after numeric literal at or near "00" of jsonpath input
- 1a                                        | f  | trailing junk after numeric literal at or near "1a" of jsonpath input
+                 jsonpath                  | ok |                                                     errmsg                                                     
+-------------------------------------------+----+----------------------------------------------------------------------------------------------------------------
+ $ ? (@ like_regex "pattern" flag "smixq") | t  | (,,,)
+ $ ? (@ like_regex "pattern" flag "a")     | f  | ("invalid input syntax for type jsonpath","Unrecognized flag character ""a"" in LIKE_REGEX predicate.",,42601)
+ @ + 1                                     | f  | ("@ is not allowed in root expressions",,,42601)
+ 00                                        | f  | ("trailing junk after numeric literal at or near ""00"" of jsonpath input",,,42601)
+ 1a                                        | f  | ("trailing junk after numeric literal at or near ""1a"" of jsonpath input",,,42601)
 (5 rows)
 
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index 6baea8fdbd..4f67aee728 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -93,9 +93,9 @@ SELECT pg_input_is_valid('{1, 1}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1}', 'line');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type line: "{1, 1}"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
@@ -105,9 +105,9 @@ SELECT pg_input_is_valid('{0, 0, 0}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{0, 0, 0}', 'line');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid line specification: A and B cannot both be zero
+                       pg_input_error_message                        
+---------------------------------------------------------------------
+ ("invalid line specification: A and B cannot both be zero",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
@@ -117,9 +117,9 @@ SELECT pg_input_is_valid('{1, 1, a}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1, a}', 'line');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type line: "{1, 1, a}"
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1, a}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
@@ -129,9 +129,9 @@ SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
 (1 row)
 
 SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
@@ -141,8 +141,8 @@ SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
 (1 row)
 
 SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index afb323fe04..14e4f73ed1 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -50,8 +50,8 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type lseg: "[(1,2),(3)]"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type lseg: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index cb646af79b..ca7c5f71ef 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -166,9 +166,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
-                   pg_input_error_message                   
-------------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+                          pg_input_error_message                          
+--------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
@@ -178,8 +178,8 @@ SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index bf681988f8..fa5308bb1f 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -360,9 +360,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+                             pg_input_error_message                              
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
@@ -372,8 +372,8 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
 (1 row)
 
 SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 46b2eab51a..574cbd17a5 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -339,9 +339,9 @@ SELECT pg_input_is_valid('\x0001', 'money');
 (1 row)
 
 SELECT pg_input_error_message('\x0001', 'money');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type money: "\x0001"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("invalid input syntax for type money: ""\\x0001""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
@@ -351,9 +351,9 @@ SELECT pg_input_is_valid('192233720368547758.07', 'money');
 (1 row)
 
 SELECT pg_input_error_message('192233720368547758.07', 'money');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "192233720368547758.07" is out of range for type money
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""192233720368547758.07"" is out of range for type money",,,22003)
 (1 row)
 
 -- documented minimums and maximums
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index e70896b754..79137d14bb 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -288,9 +288,9 @@ select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
 (1 row)
 
 select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
-            pg_input_error_message             
------------------------------------------------
- malformed multirange literal: "{[1,2], [4,5]"
+                                pg_input_error_message                                 
+---------------------------------------------------------------------------------------
+ ("malformed multirange literal: ""{[1,2], [4,5]""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
@@ -300,9 +300,9 @@ select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
 (1 row)
 
 select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 56a3f3630a..cee8603dad 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2313,9 +2313,9 @@ SELECT pg_input_is_valid('1e400000', 'numeric');
 (1 row)
 
 SELECT pg_input_error_message('1e400000', 'numeric');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+           pg_input_error_message           
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
@@ -2331,15 +2331,15 @@ SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
 (1 row)
 
 SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
- pg_input_error_message 
-------------------------
- numeric field overflow
+                                                pg_input_error_message                                                 
+-----------------------------------------------------------------------------------------------------------------------
+ ("numeric field overflow","A field with precision 7, scale 4 must round to an absolute value less than 10^3.",,22003)
 (1 row)
 
 SELECT pg_input_error_message('0x1234.567', 'numeric');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type numeric: "0x1234.567"
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("invalid input syntax for type numeric: ""0x1234.567""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/oid.out b/src/test/regress/expected/oid.out
index b664bab5f9..2a4c3b08df 100644
--- a/src/test/regress/expected/oid.out
+++ b/src/test/regress/expected/oid.out
@@ -79,9 +79,9 @@ SELECT pg_input_is_valid('01XYZ', 'oid');
 (1 row)
 
 SELECT pg_input_error_message('01XYZ', 'oid');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type oid: "01XYZ"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type oid: ""01XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('9999999999', 'oid');
@@ -91,9 +91,9 @@ SELECT pg_input_is_valid('9999999999', 'oid');
 (1 row)
 
 SELECT pg_input_error_message('9999999999', 'oid');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 -- While we're here, check oidvector as well
@@ -110,9 +110,9 @@ SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
 (1 row)
 
 SELECT pg_input_error_message('01 01XYZ', 'oidvector');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type oid: "XYZ"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type oid: ""XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
@@ -122,9 +122,9 @@ SELECT pg_input_is_valid('01 9999999999', 'oidvector');
 (1 row)
 
 SELECT pg_input_error_message('01 9999999999', 'oidvector');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 529a5e6fc2..2886091675 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -88,9 +88,9 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2),(3)]', 'path');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type path: "[(1,2),(3)]"
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
@@ -100,8 +100,8 @@ SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
 (1 row)
 
 SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type path: "[(1,2,6),(3,4,6)]"
+                        pg_input_error_message                         
+-----------------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2,6),(3,4,6)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out
index 01501f8c9b..7dfa0bae8b 100644
--- a/src/test/regress/expected/pg_lsn.out
+++ b/src/test/regress/expected/pg_lsn.out
@@ -34,9 +34,9 @@ SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
 (1 row)
 
 SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type pg_lsn: "16AE7F7"
+                    pg_input_error_message                     
+---------------------------------------------------------------
+ ("invalid input syntax for type pg_lsn: ""16AE7F7""",,,22P02)
 (1 row)
 
 -- Min/Max aggregation
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index a716ceb881..5a5b1ac4ef 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -471,8 +471,8 @@ SELECT pg_input_is_valid('1,y', 'point');
 (1 row)
 
 SELECT pg_input_error_message('1,y', 'point');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type point: "1,y"
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("invalid input syntax for type point: ""1,y""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index c7d565ad53..ef31e4c631 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -314,9 +314,9 @@ SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
 (1 row)
 
 SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type polygon: "(2.0,0.8,0.1)"
+                        pg_input_error_message                        
+----------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,0.8,0.1)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
@@ -326,8 +326,8 @@ SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
 (1 row)
 
 SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type polygon: "(2.0,xyz)"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,xyz)""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 95d1e5515f..c2e82f39e7 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2247,9 +2247,9 @@ SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
-     pg_input_error_message      
----------------------------------
- a name must follow the "/" sign
+            pg_input_error_message             
+-----------------------------------------------
+ ("a name must follow the ""/"" sign",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
@@ -2259,9 +2259,9 @@ SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem')
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-           pg_input_error_message           
---------------------------------------------
- role "regress_no_such_user" does not exist
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("role ""regress_no_such_user"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
@@ -2271,9 +2271,9 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
 (1 row)
 
 SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid mode character: must be one of ""arwdDxtXUCTcsAm""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a3e9e447af..e3f1029555 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -189,9 +189,9 @@ select pg_input_is_valid('(1,4', 'int4range');
 (1 row)
 
 select pg_input_error_message('(1,4', 'int4range');
-     pg_input_error_message      
----------------------------------
- malformed range literal: "(1,4"
+                         pg_input_error_message                          
+-------------------------------------------------------------------------
+ ("malformed range literal: ""(1,4""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('(4,1)', 'int4range');
@@ -201,9 +201,9 @@ select pg_input_is_valid('(4,1)', 'int4range');
 (1 row)
 
 select pg_input_error_message('(4,1)', 'int4range');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- range lower bound must be less than or equal to range upper bound
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("range lower bound must be less than or equal to range upper bound",,,22000)
 (1 row)
 
 select pg_input_is_valid('(4,zed)', 'int4range');
@@ -213,9 +213,9 @@ select pg_input_is_valid('(4,zed)', 'int4range');
 (1 row)
 
 select pg_input_error_message('(4,zed)', 'int4range');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('[1,2147483647]', 'int4range');
@@ -225,9 +225,9 @@ select pg_input_is_valid('[1,2147483647]', 'int4range');
 (1 row)
 
 select pg_input_error_message('[1,2147483647]', 'int4range');
- pg_input_error_message 
-------------------------
- integer out of range
+      pg_input_error_message      
+----------------------------------
+ ("integer out of range",,,22003)
 (1 row)
 
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
@@ -237,9 +237,9 @@ select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
 (1 row)
 
 select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
- pg_input_error_message 
-------------------------
- date out of range
+    pg_input_error_message     
+-------------------------------
+ ("date out of range",,,22008)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..cd1d79bad7 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -449,9 +449,9 @@ SELECT to_regnamespace('foo.bar');
 
 -- Test soft-error API
 SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
-            pg_input_error_message             
------------------------------------------------
- relation "ng_catalog.pg_class" does not exist
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ ("relation ""ng_catalog.pg_class"" does not exist",,,42P01)
 (1 row)
 
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
@@ -461,75 +461,75 @@ SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
 (1 row)
 
 SELECT pg_input_error_message('no_such_config', 'regconfig');
-                  pg_input_error_message                   
------------------------------------------------------------
- text search configuration "no_such_config" does not exist
+                         pg_input_error_message                          
+-------------------------------------------------------------------------
+ ("text search configuration ""no_such_config"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-                   pg_input_error_message                   
-------------------------------------------------------------
- text search dictionary "no_such_dictionary" does not exist
+                          pg_input_error_message                          
+--------------------------------------------------------------------------
+ ("text search dictionary ""no_such_dictionary"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-       pg_input_error_message        
--------------------------------------
- schema "nonexistent" does not exist
+              pg_input_error_message               
+---------------------------------------------------
+ ("schema ""nonexistent"" does not exist",,,3F000)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-         pg_input_error_message          
------------------------------------------
- operator does not exist: ng_catalog.||/
+               pg_input_error_message                
+-----------------------------------------------------
+ ("operator does not exist: ng_catalog.||/",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('-', 'regoper');
-     pg_input_error_message     
---------------------------------
- more than one operator named -
+           pg_input_error_message           
+--------------------------------------------
+ ("more than one operator named -",,,42725)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-              pg_input_error_message              
---------------------------------------------------
- operator does not exist: ng_catalog.+(int4,int4)
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("operator does not exist: ng_catalog.+(int4,int4)",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('-', 'regoperator');
-   pg_input_error_message    
------------------------------
- expected a left parenthesis
+         pg_input_error_message          
+-----------------------------------------
+ ("expected a left parenthesis",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-          pg_input_error_message          
-------------------------------------------
- function "ng_catalog.now" does not exist
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("function ""ng_catalog.now"" does not exist",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-              pg_input_error_message               
----------------------------------------------------
- function "ng_catalog.abs(numeric)" does not exist
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("function ""ng_catalog.abs(numeric)"" does not exist",,,42883)
 (1 row)
 
 SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-    pg_input_error_message    
-------------------------------
- expected a right parenthesis
+          pg_input_error_message          
+------------------------------------------
+ ("expected a right parenthesis",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-           pg_input_error_message           
---------------------------------------------
- role "regress_regrole_test" does not exist
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("role ""regress_regrole_test"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_error_message('no_such_type', 'regtype');
-       pg_input_error_message       
-------------------------------------
- type "no_such_type" does not exist
+              pg_input_error_message              
+--------------------------------------------------
+ ("type ""no_such_type"" does not exist",,,42704)
 (1 row)
 
 -- Some cases that should be soft errors, but are not yet
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 801d9e556b..a9fb5320e3 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -89,15 +89,15 @@ SELECT pg_input_is_valid('(1,zed)', 'complex');
 (1 row)
 
 SELECT pg_input_error_message('(1,zed)', 'complex');
-                pg_input_error_message                 
--------------------------------------------------------
- invalid input syntax for type double precision: "zed"
+                       pg_input_error_message                        
+---------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""zed""",,,22P02)
 (1 row)
 
 SELECT pg_input_error_message('(1,1e400)', 'complex');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 create temp table quadtable(f1 int, q quad);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index f028c1f10f..28c78c960b 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -281,21 +281,21 @@ SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
 (1 row)
 
 SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-             pg_input_error_message             
-------------------------------------------------
- invalid hexadecimal data: odd number of digits
+                   pg_input_error_message                   
+------------------------------------------------------------
+ ("invalid hexadecimal data: odd number of digits",,,22023)
 (1 row)
 
 SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-     pg_input_error_message     
---------------------------------
- invalid hexadecimal digit: "x"
+            pg_input_error_message            
+----------------------------------------------
+ ("invalid hexadecimal digit: ""x""",,,22023)
 (1 row)
 
 SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
-       pg_input_error_message        
--------------------------------------
- invalid input syntax for type bytea
+             pg_input_error_message              
+-------------------------------------------------
+ ("invalid input syntax for type bytea",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out
index ff67ed43f0..7ee891cc1a 100644
--- a/src/test/regress/expected/tid.out
+++ b/src/test/regress/expected/tid.out
@@ -25,9 +25,9 @@ SELECT pg_input_is_valid('(0)', 'tid');
 (1 row)
 
 SELECT pg_input_error_message('(0)', 'tid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type tid: "(0)"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(0,-1)', 'tid');
@@ -37,9 +37,9 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
 (1 row)
 
 SELECT pg_input_error_message('(0,-1)', 'tid');
-           pg_input_error_message            
----------------------------------------------
- invalid input syntax for type tid: "(0,-1)"
+                  pg_input_error_message                   
+-----------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0,-1)""",,,22P02)
 (1 row)
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index a44caededd..79de9377db 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -134,15 +134,15 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
 (1 row)
 
 SELECT pg_input_error_message('25:00:00', 'time');
-             pg_input_error_message             
-------------------------------------------------
- date/time field value out of range: "25:00:00"
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00""",,,22008)
 (1 row)
 
 SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type time: "15:36:39 America/New_York"
+                            pg_input_error_message                             
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type time: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index eef2f7001c..eafccc38ac 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -145,15 +145,15 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'timestamp');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type timestamp: "garbage"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("invalid input syntax for type timestamp: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index b85a93a3c2..73c7d70455 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -196,15 +196,15 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
 (1 row)
 
 SELECT pg_input_error_message('garbage', 'timestamptz');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type timestamp with time zone: "garbage"
+                             pg_input_error_message                              
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type timestamp with time zone: ""garbage""",,,22007)
 (1 row)
 
 SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 984285663b..665fa4495c 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -151,15 +151,15 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
 (1 row)
 
 SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-               pg_input_error_message               
-----------------------------------------------------
- date/time field value out of range: "25:00:00 PDT"
+                      pg_input_error_message                      
+------------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00 PDT""",,,22008)
 (1 row)
 
 SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
-                             pg_input_error_message                             
---------------------------------------------------------------------------------
- invalid input syntax for type time with time zone: "15:36:39 America/New_York"
+                                    pg_input_error_message                                    
+----------------------------------------------------------------------------------------------
+ ("invalid input syntax for type time with time zone: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index a8785cd708..35b19814c4 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -103,9 +103,9 @@ SELECT pg_input_is_valid($$''$$, 'tsvector');
 (1 row)
 
 SELECT pg_input_error_message($$''$$, 'tsvector');
-     pg_input_error_message     
---------------------------------
- syntax error in tsvector: "''"
+            pg_input_error_message            
+----------------------------------------------
+ ("syntax error in tsvector: ""''""",,,42601)
 (1 row)
 
 --Base tsquery test
@@ -405,15 +405,15 @@ SELECT pg_input_is_valid('foo!', 'tsquery');
 (1 row)
 
 SELECT pg_input_error_message('foo!', 'tsquery');
-     pg_input_error_message      
----------------------------------
- syntax error in tsquery: "foo!"
+            pg_input_error_message             
+-----------------------------------------------
+ ("syntax error in tsquery: ""foo!""",,,42601)
 (1 row)
 
 SELECT pg_input_error_message('a <100000> b', 'tsquery');
-                                pg_input_error_message                                 
----------------------------------------------------------------------------------------
- distance in phrase operator must be an integer value between zero and 16384 inclusive
+                                      pg_input_error_message                                       
+---------------------------------------------------------------------------------------------------
+ ("distance in phrase operator must be an integer value between zero and 16384 inclusive",,,22023)
 (1 row)
 
 --comparisons
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 0f47232009..3934626dda 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -47,9 +47,9 @@ SELECT pg_input_is_valid('11', 'uuid');
 (1 row)
 
 SELECT pg_input_error_message('11', 'uuid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type uuid: "11"
+                 pg_input_error_message                 
+--------------------------------------------------------
+ ("invalid input syntax for type uuid: ""11""",,,22P02)
 (1 row)
 
 --inserting three input formats
diff --git a/src/test/regress/expected/varchar.out b/src/test/regress/expected/varchar.out
index 62b683d86f..d93dc1d9f9 100644
--- a/src/test/regress/expected/varchar.out
+++ b/src/test/regress/expected/varchar.out
@@ -125,8 +125,8 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_1.out b/src/test/regress/expected/varchar_1.out
index 6690f81c0b..ee0e920e84 100644
--- a/src/test/regress/expected/varchar_1.out
+++ b/src/test/regress/expected/varchar_1.out
@@ -125,8 +125,8 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_2.out b/src/test/regress/expected/varchar_2.out
index ad8aa7c693..3b663298ab 100644
--- a/src/test/regress/expected/varchar_2.out
+++ b/src/test/regress/expected/varchar_2.out
@@ -125,8 +125,8 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
 (1 row)
 
 SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+                  pg_input_error_message                  
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index e62f701943..754ff6b725 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -44,9 +44,9 @@ SELECT pg_input_is_valid('asdf', 'xid');
 (1 row)
 
 SELECT pg_input_error_message('0xffffffffff', 'xid');
-              pg_input_error_message               
----------------------------------------------------
- value "0xffffffffff" is out of range for type xid
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ ("value ""0xffffffffff"" is out of range for type xid",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('42', 'xid8');
@@ -62,9 +62,9 @@ SELECT pg_input_is_valid('asdf', 'xid8');
 (1 row)
 
 SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "0xffffffffffffffffffff" is out of range for type xid8
+                           pg_input_error_message                           
+----------------------------------------------------------------------------
+ ("value ""0xffffffffffffffffffff"" is out of range for type xid8",,,22003)
 (1 row)
 
 -- equality
@@ -224,9 +224,9 @@ select pg_input_is_valid('31:12:', 'pg_snapshot');
 (1 row)
 
 select pg_input_error_message('31:12:', 'pg_snapshot');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type pg_snapshot: "31:12:"
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""31:12:""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
@@ -236,9 +236,9 @@ select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
 (1 row)
 
 select pg_input_error_message('12:16:14,13', 'pg_snapshot');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type pg_snapshot: "12:16:14,13"
+                         pg_input_error_message                         
+------------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""12:16:14,13""",,,22P02)
 (1 row)
 
 create temp table snapshot_test (
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..da6ac19ccb 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -31,9 +31,9 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
-------------------------
+SELECT message FROM pg_input_error_message('<value>one</', 'xml');
+       message       
+---------------------
  invalid XML content
 (1 row)
 
@@ -43,8 +43,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 378b412db0..9451c3808a 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -29,13 +29,13 @@ DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_message('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlcomment('test');
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 42055c5003..0d1e52855f 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -29,8 +29,8 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
+SELECT message FROM pg_input_error_message('<value>one</', 'xml');
+       message          
 ------------------------
  invalid XML content
 (1 row)
@@ -41,8 +41,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ddff459297..4dea563094 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -12,9 +12,9 @@ SELECT * FROM xmltest;
 -- test non-throwing API, too
 SELECT pg_input_is_valid('<value>one</value>', 'xml');
 SELECT pg_input_is_valid('<value>one</', 'xml');
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_message('<value>one</', 'xml');
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 
 
 SELECT xmlcomment('test');
-- 
2.25.1

#8Corey Huinker
corey.huinker@gmail.com
In reply to: Nathan Bossart (#7)
Re: verbose mode for pg_input_error_message?

On Thu, Feb 23, 2023 at 4:47 PM Nathan Bossart <nathandbossart@gmail.com>
wrote:

On Thu, Feb 23, 2023 at 11:30:38AM -0800, Nathan Bossart wrote:

Will post a new version shortly.

As promised...

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

Looks good to me, passes make check-world. Thanks for slogging through this.

#9Michael Paquier
michael@paquier.xyz
In reply to: Corey Huinker (#8)
Re: verbose mode for pg_input_error_message?

On Fri, Feb 24, 2023 at 05:36:42PM -0500, Corey Huinker wrote:

Looks good to me, passes make check-world. Thanks for slogging through this.

FWIW, I agree that switching pg_input_error_message() to return a row
would be nicer in the long-run than just getting an error message
because it has the merit to be extensible at will with all the data
we'd like to attach to it (I suspect that getting more fields is not
much likely, but who knows..).

pg_input_error_message() does not strike me as a good function name,
though, because it now returns much more than an error message.
Hence, couldn't something like pg_input_error() be better, because
more generic?
--
Michael

#10Nathan Bossart
nathandbossart@gmail.com
In reply to: Michael Paquier (#9)
Re: verbose mode for pg_input_error_message?

On Sat, Feb 25, 2023 at 01:39:21PM +0900, Michael Paquier wrote:

pg_input_error_message() does not strike me as a good function name,
though, because it now returns much more than an error message.
Hence, couldn't something like pg_input_error() be better, because
more generic?

I personally think the existing name is fine. It returns the error
message, which includes the primary, detail, and hint messages. Also, I'm
not sure that pg_input_error() is descriptive enough. That being said, I'm
happy to run the sed command to change the name to whatever folks think is
best.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Nathan Bossart (#10)
Re: verbose mode for pg_input_error_message?

Nathan Bossart <nathandbossart@gmail.com> writes:

On Sat, Feb 25, 2023 at 01:39:21PM +0900, Michael Paquier wrote:

pg_input_error_message() does not strike me as a good function name,
though, because it now returns much more than an error message.
Hence, couldn't something like pg_input_error() be better, because
more generic?

I personally think the existing name is fine. It returns the error
message, which includes the primary, detail, and hint messages. Also, I'm
not sure that pg_input_error() is descriptive enough. That being said, I'm
happy to run the sed command to change the name to whatever folks think is
best.

Maybe pg_input_error_info()? I tend to agree with Michael that as
soon as you throw things like the SQLSTATE code into it, "message"
seems not very apropos. I'm not dead set on that position, though.

regards, tom lane

#12Nathan Bossart
nathandbossart@gmail.com
In reply to: Tom Lane (#11)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On Sat, Feb 25, 2023 at 08:07:33PM -0500, Tom Lane wrote:

Maybe pg_input_error_info()? I tend to agree with Michael that as
soon as you throw things like the SQLSTATE code into it, "message"
seems not very apropos. I'm not dead set on that position, though.

pg_input_error_info() seems more descriptive to me. I changed the name to
that in v4.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

Attachments:

v4-0001-add-details-to-pg_input_error_message-and-rename-.patchtext/x-diff; charset=us-asciiDownload
From e06bba8374ba486c8593138b10a256aeef42a8af Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Thu, 23 Feb 2023 10:31:24 -0800
Subject: [PATCH v4 1/1] add details to pg_input_error_message and rename to
 pg_input_error_info

---
 contrib/cube/expected/cube.out                |   8 +-
 contrib/cube/sql/cube.sql                     |   2 +-
 contrib/hstore/expected/hstore.out            |  16 +--
 contrib/hstore/sql/hstore.sql                 |   4 +-
 contrib/intarray/expected/_int.out            |  12 +-
 contrib/intarray/sql/_int.sql                 |   2 +-
 contrib/isn/expected/isn.out                  |  12 +-
 contrib/isn/sql/isn.sql                       |   2 +-
 contrib/ltree/expected/ltree.out              |  22 ++--
 contrib/ltree/sql/ltree.sql                   |   2 +-
 contrib/seg/expected/seg.out                  |  18 +--
 contrib/seg/sql/seg.sql                       |   2 +-
 doc/src/sgml/func.sgml                        |  33 +++--
 src/backend/utils/adt/misc.c                  |  42 +++++--
 src/include/catalog/pg_proc.dat               |  10 +-
 src/test/regress/expected/arrays.out          |   8 +-
 src/test/regress/expected/bit.out             |  40 +++---
 src/test/regress/expected/boolean.out         |   8 +-
 src/test/regress/expected/box.out             |  16 +--
 src/test/regress/expected/char.out            |   8 +-
 src/test/regress/expected/char_1.out          |   8 +-
 src/test/regress/expected/char_2.out          |   8 +-
 src/test/regress/expected/date.out            |  16 +--
 src/test/regress/expected/domain.out          |  34 +++---
 src/test/regress/expected/enum.out            |  16 +--
 .../expected/float4-misrounded-input.out      |   4 +-
 src/test/regress/expected/float4.out          |   8 +-
 src/test/regress/expected/float8.out          |   8 +-
 src/test/regress/expected/geometry.out        |  16 +--
 src/test/regress/expected/inet.out            |  24 ++--
 src/test/regress/expected/int2.out            |  24 ++--
 src/test/regress/expected/int4.out            |   8 +-
 src/test/regress/expected/int8.out            |   8 +-
 src/test/regress/expected/interval.out        |  16 +--
 src/test/regress/expected/json.out            |   8 +-
 src/test/regress/expected/json_encoding.out   |   8 +-
 src/test/regress/expected/json_encoding_1.out |   8 +-
 src/test/regress/expected/jsonb.out           |  16 +--
 src/test/regress/expected/jsonpath.out        |  16 +--
 src/test/regress/expected/line.out            |  40 +++---
 src/test/regress/expected/lseg.out            |   8 +-
 src/test/regress/expected/macaddr.out         |  16 +--
 src/test/regress/expected/macaddr8.out        |  16 +--
 src/test/regress/expected/money.out           |  16 +--
 src/test/regress/expected/multirangetypes.out |  16 +--
 src/test/regress/expected/numeric.out         |  24 ++--
 src/test/regress/expected/oid.out             |  32 ++---
 src/test/regress/expected/path.out            |  16 +--
 src/test/regress/expected/pg_lsn.out          |   8 +-
 src/test/regress/expected/point.out           |   8 +-
 src/test/regress/expected/polygon.out         |  16 +--
 src/test/regress/expected/privileges.out      |  24 ++--
 src/test/regress/expected/rangetypes.out      |  40 +++---
 src/test/regress/expected/regproc.out         | 114 +++++++++---------
 src/test/regress/expected/rowtypes.out        |  16 +--
 src/test/regress/expected/strings.out         |  24 ++--
 src/test/regress/expected/tid.out             |  16 +--
 src/test/regress/expected/time.out            |  16 +--
 src/test/regress/expected/timestamp.out       |  16 +--
 src/test/regress/expected/timestamptz.out     |  16 +--
 src/test/regress/expected/timetz.out          |  16 +--
 src/test/regress/expected/tstypes.out         |  24 ++--
 src/test/regress/expected/uuid.out            |   8 +-
 src/test/regress/expected/varchar.out         |   8 +-
 src/test/regress/expected/varchar_1.out       |   8 +-
 src/test/regress/expected/varchar_2.out       |   8 +-
 src/test/regress/expected/xid.out             |  32 ++---
 src/test/regress/expected/xml.out             |  10 +-
 src/test/regress/expected/xml_1.out           |   4 +-
 src/test/regress/expected/xml_2.out           |   8 +-
 src/test/regress/sql/arrays.sql               |   2 +-
 src/test/regress/sql/bit.sql                  |  10 +-
 src/test/regress/sql/boolean.sql              |   2 +-
 src/test/regress/sql/box.sql                  |   4 +-
 src/test/regress/sql/char.sql                 |   2 +-
 src/test/regress/sql/date.sql                 |   4 +-
 src/test/regress/sql/domain.sql               |  10 +-
 src/test/regress/sql/enum.sql                 |   4 +-
 src/test/regress/sql/float4.sql               |   2 +-
 src/test/regress/sql/float8.sql               |   2 +-
 src/test/regress/sql/geometry.sql             |   4 +-
 src/test/regress/sql/inet.sql                 |   6 +-
 src/test/regress/sql/int2.sql                 |   6 +-
 src/test/regress/sql/int4.sql                 |   2 +-
 src/test/regress/sql/int8.sql                 |   2 +-
 src/test/regress/sql/interval.sql             |   4 +-
 src/test/regress/sql/json.sql                 |   2 +-
 src/test/regress/sql/json_encoding.sql        |   2 +-
 src/test/regress/sql/jsonb.sql                |   4 +-
 src/test/regress/sql/jsonpath.sql             |   2 +-
 src/test/regress/sql/line.sql                 |  10 +-
 src/test/regress/sql/lseg.sql                 |   2 +-
 src/test/regress/sql/macaddr.sql              |   4 +-
 src/test/regress/sql/macaddr8.sql             |   4 +-
 src/test/regress/sql/money.sql                |   4 +-
 src/test/regress/sql/multirangetypes.sql      |   4 +-
 src/test/regress/sql/numeric.sql              |   6 +-
 src/test/regress/sql/oid.sql                  |   8 +-
 src/test/regress/sql/path.sql                 |   4 +-
 src/test/regress/sql/pg_lsn.sql               |   2 +-
 src/test/regress/sql/point.sql                |   2 +-
 src/test/regress/sql/polygon.sql              |   4 +-
 src/test/regress/sql/privileges.sql           |   6 +-
 src/test/regress/sql/rangetypes.sql           |  10 +-
 src/test/regress/sql/regproc.sql              |  34 +++---
 src/test/regress/sql/rowtypes.sql             |   4 +-
 src/test/regress/sql/strings.sql              |   6 +-
 src/test/regress/sql/tid.sql                  |   4 +-
 src/test/regress/sql/time.sql                 |   4 +-
 src/test/regress/sql/timestamp.sql            |   4 +-
 src/test/regress/sql/timestamptz.sql          |   4 +-
 src/test/regress/sql/timetz.sql               |   4 +-
 src/test/regress/sql/tstypes.sql              |   6 +-
 src/test/regress/sql/uuid.sql                 |   2 +-
 src/test/regress/sql/varchar.sql              |   2 +-
 src/test/regress/sql/xid.sql                  |   8 +-
 src/test/regress/sql/xml.sql                  |   4 +-
 117 files changed, 708 insertions(+), 669 deletions(-)

diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index dc23e5ccc0..5e2bade19c 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -344,10 +344,10 @@ SELECT pg_input_is_valid('-1e-700', 'cube');
  f
 (1 row)
 
-SELECT pg_input_error_message('-1e-700', 'cube');
-               pg_input_error_message                
------------------------------------------------------
- "-1e-700" is out of range for type double precision
+SELECT pg_input_error_info('-1e-700', 'cube');
+                        pg_input_error_info                        
+-------------------------------------------------------------------
+ ("""-1e-700"" is out of range for type double precision",,,22003)
 (1 row)
 
 --
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 384883d16e..2bb96e3490 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -83,7 +83,7 @@ SELECT '-1e-700'::cube AS cube; -- out of range
 SELECT pg_input_is_valid('(1,2)', 'cube');
 SELECT pg_input_is_valid('[(1),]', 'cube');
 SELECT pg_input_is_valid('-1e-700', 'cube');
-SELECT pg_input_error_message('-1e-700', 'cube');
+SELECT pg_input_error_info('-1e-700', 'cube');
 
 --
 -- Testing building cubes from float8 values
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index d6faa91867..3d391a3453 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -265,16 +265,16 @@ select pg_input_is_valid('a=b', 'hstore');
  f
 (1 row)
 
-select pg_input_error_message('a=b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "b" at position 2
+select pg_input_error_info('a=b', 'hstore');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""b"" at position 2",,,42601)
 (1 row)
 
-select pg_input_error_message(' =>b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "=" at position 1
+select pg_input_error_info(' =>b', 'hstore');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("syntax error in hstore, near ""="" at position 1",,,42601)
 (1 row)
 
 -- -> operator
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index 15f4f71416..3cd009c62a 100644
--- a/contrib/hstore/sql/hstore.sql
+++ b/contrib/hstore/sql/hstore.sql
@@ -60,8 +60,8 @@ select 'aa=>"'::hstore;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('a=>b', 'hstore');
 select pg_input_is_valid('a=b', 'hstore');
-select pg_input_error_message('a=b', 'hstore');
-select pg_input_error_message(' =>b', 'hstore');
+select pg_input_error_info('a=b', 'hstore');
+select pg_input_error_info(' =>b', 'hstore');
 
 
 -- -> operator
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index c953065a5c..3645426165 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -401,16 +401,16 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 -- test non-error-throwing input
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       pg_input_error_info(str,'query_int') as errmsg
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
       AS a(str);
-    query_int    | ok |    errmsg    
------------------+----+--------------
- 1&(2&(4&(5|6))) | t  | 
- 1#(2&(4&(5&6))) | f  | syntax error
- foo             | f  | syntax error
+    query_int    | ok |          errmsg          
+-----------------+----+--------------------------
+ 1&(2&(4&(5|6))) | t  | (,,,)
+ 1#(2&(4&(5&6))) | f  | ("syntax error",,,42601)
+ foo             | f  | ("syntax error",,,42601)
 (3 rows)
 
 CREATE TABLE test__int( a int[] );
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
index 4c9ba4c1fb..6dde5c5e33 100644
--- a/contrib/intarray/sql/_int.sql
+++ b/contrib/intarray/sql/_int.sql
@@ -79,7 +79,7 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       pg_input_error_info(str,'query_int') as errmsg
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out
index 72171b2790..efc999ab37 100644
--- a/contrib/isn/expected/isn.out
+++ b/contrib/isn/expected/isn.out
@@ -263,16 +263,16 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       pg_input_error_info(str,typ) as errmsg
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
       AS a(str,typ);
-      isn      | type  | ok |                         errmsg                         
----------------+-------+----+--------------------------------------------------------
- 9780123456786 | UPC   | f  | cannot cast ISBN to UPC for number: "9780123456786"
- postgresql... | EAN13 | f  | invalid input syntax for EAN13 number: "postgresql..."
- 9771234567003 | ISSN  | t  | 
+      isn      | type  | ok |                                errmsg                                
+---------------+-------+----+----------------------------------------------------------------------
+ 9780123456786 | UPC   | f  | ("cannot cast ISBN to UPC for number: ""9780123456786""",,,22P02)
+ postgresql... | EAN13 | f  | ("invalid input syntax for EAN13 number: ""postgresql...""",,,22P02)
+ 9771234567003 | ISSN  | t  | (,,,)
 (3 rows)
 
 --
diff --git a/contrib/isn/sql/isn.sql b/contrib/isn/sql/isn.sql
index 6426cb42a0..9fcb1f5bfe 100644
--- a/contrib/isn/sql/isn.sql
+++ b/contrib/isn/sql/isn.sql
@@ -110,7 +110,7 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       pg_input_error_info(str,typ) as errmsg
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index d2a53b9f0c..bc2eda125c 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -8101,7 +8101,7 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 -- test non-error-throwing input
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       pg_input_error_info(str,typ) as errmsg
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
@@ -8111,15 +8111,15 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
       AS a(str,typ);
-     value      |   type    | ok |               errmsg               
-----------------+-----------+----+------------------------------------
- .2.3           | ltree     | f  | ltree syntax error at character 1
- 1.2.           | ltree     | f  | ltree syntax error
- 1.2.3          | ltree     | t  | 
- @.2.3          | lquery    | f  | lquery syntax error at character 1
-  2.3           | lquery    | f  | lquery syntax error at character 1
- 1.2.3          | lquery    | t  | 
- $tree & aWdf@* | ltxtquery | f  | operand syntax error
- !tree & aWdf@* | ltxtquery | t  | 
+     value      |   type    | ok |                          errmsg                          
+----------------+-----------+----+----------------------------------------------------------
+ .2.3           | ltree     | f  | ("ltree syntax error at character 1",,,42601)
+ 1.2.           | ltree     | f  | ("ltree syntax error","Unexpected end of input.",,42601)
+ 1.2.3          | ltree     | t  | (,,,)
+ @.2.3          | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+  2.3           | lquery    | f  | ("lquery syntax error at character 1",,,42601)
+ 1.2.3          | lquery    | t  | (,,,)
+ $tree & aWdf@* | ltxtquery | f  | ("operand syntax error",,,42601)
+ !tree & aWdf@* | ltxtquery | t  | (,,,)
 (8 rows)
 
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index 4a6e6266c3..ab30792354 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -393,7 +393,7 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       pg_input_error_info(str,typ) as errmsg
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 7a06113ed8..6d8831d077 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1276,20 +1276,20 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 -- test non error throwing API
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       pg_input_error_info(str,'seg') as errmsg
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
                   'ABC',
                   '1 e7',
                   '1e700']) str;
-   seg    | ok |                errmsg                 
-----------+----+---------------------------------------
- -1 .. 1  | t  | 
- 100(+-)1 | t  | 
-          | f  | bad seg representation
- ABC      | f  | bad seg representation
- 1 e7     | f  | bad seg representation
- 1e700    | f  | "1e700" is out of range for type real
+   seg    | ok |                              errmsg                               
+----------+----+-------------------------------------------------------------------
+ -1 .. 1  | t  | (,,,)
+ 100(+-)1 | t  | (,,,)
+          | f  | ("bad seg representation","syntax error at end of input",,42601)
+ ABC      | f  | ("bad seg representation","syntax error at or near ""A""",,42601)
+ 1 e7     | f  | ("bad seg representation","syntax error at or near ""e""",,42601)
+ 1e700    | f  | ("""1e700"" is out of range for type real",,,22003)
 (6 rows)
 
diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql
index b9a5d05d09..b2a96e84ba 100644
--- a/contrib/seg/sql/seg.sql
+++ b/contrib/seg/sql/seg.sql
@@ -244,7 +244,7 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       pg_input_error_info(str,'seg') as errmsg
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0cbdf63632..97b3f1c1a6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24775,19 +24775,23 @@ SELECT collation for ('foo' COLLATE "de_DE");
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
-         <primary>pg_input_error_message</primary>
+         <primary>pg_input_error_info</primary>
         </indexterm>
-        <function>pg_input_error_message</function> (
+        <function>pg_input_error_info</function> (
           <parameter>string</parameter> <type>text</type>,
           <parameter>type</parameter> <type>text</type>
         )
-        <returnvalue>text</returnvalue>
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
        </para>
        <para>
         Tests whether the given <parameter>string</parameter> is valid
-        input for the specified data type; if not, return the error
-        message that would have been thrown.  If the input is valid, the
-        result is NULL.  The inputs are the same as
+        input for the specified data type; if not, return the details of
+        the error would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
         for <function>pg_input_is_valid</function>.
        </para>
        <para>
@@ -24798,12 +24802,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
         directly.
         </para>
         <para>
-         <literal>pg_input_error_message('42000000000', 'integer')</literal>
-         <returnvalue>value "42000000000" is out of range for type integer</returnvalue>
-        </para>
-        <para>
-         <literal>pg_input_error_message('1234.567', 'numeric(7,4)')</literal>
-         <returnvalue>numeric field overflow</returnvalue>
+<programlisting>
+SELECT * FROM pg_input_error_info('42000000000', 'integer');
+                       message                        | detail | hint | sql_error_code
+------------------------------------------------------+--------+------+----------------
+ value "42000000000" is out of range for type integer |        |      | 22003
+
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
+</programlisting>
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index f95256efd3..182d16cdcd 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -660,32 +660,58 @@ pg_input_is_valid(PG_FUNCTION_ARGS)
 }
 
 /*
- * pg_input_error_message - test whether string is valid input for datatype.
+ * pg_input_error_info - test whether string is valid input for datatype.
  *
- * Returns NULL if OK, else the primary message string from the error.
+ * Returns NULL if OK, else the primary message, detail message, hint message,
+ * and sql error code from the error.
  *
  * This will only work usefully if the datatype's input function has been
  * updated to return "soft" errors via errsave/ereturn.
  */
 Datum
-pg_input_error_message(PG_FUNCTION_ARGS)
+pg_input_error_info(PG_FUNCTION_ARGS)
 {
 	text	   *txt = PG_GETARG_TEXT_PP(0);
 	text	   *typname = PG_GETARG_TEXT_PP(1);
 	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
 	/* Enable details_wanted */
 	escontext.details_wanted = true;
 
 	if (pg_input_is_valid_common(fcinfo, txt, typname,
 								 &escontext))
-		PG_RETURN_NULL();
+		memset(isnull, true, sizeof(isnull));
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
+
+		memset(isnull, false, sizeof(isnull));
+
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
 
-	Assert(escontext.error_occurred);
-	Assert(escontext.error_data != NULL);
-	Assert(escontext.error_data->message != NULL);
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
 
-	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /* Common subroutine for the above */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e2a7642a2b..505595620e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7118,9 +7118,13 @@
   proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool',
   proargtypes => 'text text', prosrc => 'pg_input_is_valid' },
 { oid => '8051',
-  descr => 'get error message if string is not valid input for data type',
-  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
-  proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_info', provolatile => 's', prorettype => 'record',
+  proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_info' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..c840cc7765 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -201,10 +201,10 @@ SELECT pg_input_is_valid('{1,zed}', 'integer[]');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+SELECT pg_input_error_info('{1,zed}', 'integer[]');
+                    pg_input_error_info                     
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 -- test mixed slice/scalar subscripting
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 209044713c..411e2abe23 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -753,10 +753,10 @@ SELECT pg_input_is_valid('01010001', 'bit(10)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010001', 'bit(10)');
-             pg_input_error_message              
--------------------------------------------------
- bit string length 8 does not match type bit(10)
+SELECT pg_input_error_info('01010001', 'bit(10)');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("bit string length 8 does not match type bit(10)",,,22026)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
@@ -765,10 +765,10 @@ SELECT pg_input_is_valid('01010Z01', 'bit(8)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT pg_input_error_info('01010Z01', 'bit(8)');
+              pg_input_error_info              
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
@@ -777,10 +777,10 @@ SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT pg_input_error_info('x01010Z01', 'bit(32)');
+                pg_input_error_info                 
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
@@ -789,10 +789,10 @@ SELECT pg_input_is_valid('01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'varbit');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT pg_input_error_info('01010Z01', 'varbit');
+              pg_input_error_info              
+-----------------------------------------------
+ ("""Z"" is not a valid binary digit",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
@@ -801,9 +801,9 @@ SELECT pg_input_is_valid('x01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'varbit');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT pg_input_error_info('x01010Z01', 'varbit');
+                pg_input_error_info                 
+----------------------------------------------------
+ ("""Z"" is not a valid hexadecimal digit",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/boolean.out b/src/test/regress/expected/boolean.out
index 977124b20b..cbc4429a11 100644
--- a/src/test/regress/expected/boolean.out
+++ b/src/test/regress/expected/boolean.out
@@ -155,10 +155,10 @@ SELECT pg_input_is_valid('asdf', 'bool');
  f
 (1 row)
 
-SELECT pg_input_error_message('junk', 'bool');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type boolean: "junk"
+SELECT pg_input_error_info('junk', 'bool');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("invalid input syntax for type boolean: ""junk""",,,22P02)
 (1 row)
 
 -- and, or, not in qualifications
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 0d70194def..406ee5b815 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -646,10 +646,10 @@ SELECT pg_input_is_valid('200', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('200', 'box');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type box: "200"
+SELECT pg_input_error_info('200', 'box');
+                  pg_input_error_info                   
+--------------------------------------------------------
+ ("invalid input syntax for type box: ""200""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
@@ -658,9 +658,9 @@ SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-                   pg_input_error_message                    
--------------------------------------------------------------
- invalid input syntax for type box: "((200,300),(500, xyz))"
+SELECT pg_input_error_info('((200,300),(500, xyz))', 'box');
+                            pg_input_error_info                            
+---------------------------------------------------------------------------
+ ("invalid input syntax for type box: ""((200,300),(500, xyz))""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/char.out b/src/test/regress/expected/char.out
index 199001b2fe..58cdd54ffb 100644
--- a/src/test/regress/expected/char.out
+++ b/src/test/regress/expected/char.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT pg_input_error_info('abcde', 'char(4)');
+               pg_input_error_info                
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_1.out b/src/test/regress/expected/char_1.out
index 3dcb0daa0d..c45fe2a400 100644
--- a/src/test/regress/expected/char_1.out
+++ b/src/test/regress/expected/char_1.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT pg_input_error_info('abcde', 'char(4)');
+               pg_input_error_info                
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_2.out b/src/test/regress/expected/char_2.out
index dd5d34fe8d..1281ba4394 100644
--- a/src/test/regress/expected/char_2.out
+++ b/src/test/regress/expected/char_2.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT pg_input_error_info('abcde', 'char(4)');
+               pg_input_error_info                
+--------------------------------------------------
+ ("value too long for type character(4)",,,22001)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index c0dec448e1..4a496aec5b 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -859,16 +859,16 @@ SELECT pg_input_is_valid('6874898-01-01', 'date');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'date');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type date: "garbage"
+SELECT pg_input_error_info('garbage', 'date');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("invalid input syntax for type date: ""garbage""",,,22007)
 (1 row)
 
-SELECT pg_input_error_message('6874898-01-01', 'date');
-       pg_input_error_message       
-------------------------------------
- date out of range: "6874898-01-01"
+SELECT pg_input_error_info('6874898-01-01', 'date');
+               pg_input_error_info                
+--------------------------------------------------
+ ("date out of range: ""6874898-01-01""",,,22008)
 (1 row)
 
 RESET datestyle;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 25f6bb9e1f..b832b146f7 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -108,32 +108,32 @@ select pg_input_is_valid('-1', 'positiveint');
  f
 (1 row)
 
-select pg_input_error_message('junk', 'positiveint');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type integer: "junk"
+select pg_input_error_info('junk', 'positiveint');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("invalid input syntax for type integer: ""junk""",,,22P02)
 (1 row)
 
-select pg_input_error_message('-1', 'positiveint');
-                           pg_input_error_message                           
-----------------------------------------------------------------------------
- value for domain positiveint violates check constraint "positiveint_check"
+select pg_input_error_info('-1', 'positiveint');
+                                   pg_input_error_info                                    
+------------------------------------------------------------------------------------------
+ ("value for domain positiveint violates check constraint ""positiveint_check""",,,23514)
 (1 row)
 
-select pg_input_error_message('junk', 'weirdfloat');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type double precision: "junk"
+select pg_input_error_info('junk', 'weirdfloat');
+                         pg_input_error_info                          
+----------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""junk""",,,22P02)
 (1 row)
 
-select pg_input_error_message('0.01', 'weirdfloat');
-                          pg_input_error_message                          
---------------------------------------------------------------------------
- value for domain weirdfloat violates check constraint "weirdfloat_check"
+select pg_input_error_info('0.01', 'weirdfloat');
+                                  pg_input_error_info                                   
+----------------------------------------------------------------------------------------
+ ("value for domain weirdfloat violates check constraint ""weirdfloat_check""",,,23514)
 (1 row)
 
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select pg_input_error_info('0', 'weirdfloat');
 ERROR:  division by zero
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4b45fcf8f0..26671b23b7 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -37,16 +37,16 @@ SELECT pg_input_is_valid('mauve', 'rainbow');
  f
 (1 row)
 
-SELECT pg_input_error_message('mauve', 'rainbow');
-            pg_input_error_message             
------------------------------------------------
- invalid input value for enum rainbow: "mauve"
+SELECT pg_input_error_info('mauve', 'rainbow');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""mauve""",,,22P02)
 (1 row)
 
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
-                                                                                                                                          pg_input_error_message                                                                                                                                          
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
+SELECT pg_input_error_info(repeat('too_long', 32), 'rainbow');
+                                                                                                                                                  pg_input_error_info                                                                                                                                                   
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ("invalid input value for enum rainbow: ""too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
index 24fde6cc9f..12e18ff465 100644
--- a/src/test/regress/expected/float4-misrounded-input.out
+++ b/src/test/regress/expected/float4-misrounded-input.out
@@ -100,8 +100,8 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
+SELECT pg_input_error_info('1e400', 'float4');
+          pg_input_error_info          
 ---------------------------------------
  "1e400" is out of range for type real
 (1 row)
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 1d7090a90d..94d68adb7b 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -100,10 +100,10 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+SELECT pg_input_error_info('1e400', 'float4');
+                 pg_input_error_info                 
+-----------------------------------------------------
+ ("""1e400"" is out of range for type real",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 2b25784f7f..06cc8c6537 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('1e4000', 'float8');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e4000', 'float8');
-               pg_input_error_message               
-----------------------------------------------------
- "1e4000" is out of range for type double precision
+SELECT pg_input_error_info('1e4000', 'float8');
+                       pg_input_error_info                        
+------------------------------------------------------------------
+ ("""1e4000"" is out of range for type double precision",,,22003)
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 291cacdf4f..76ad614b61 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5302,10 +5302,10 @@ SELECT pg_input_is_valid('(1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,', 'circle');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type circle: "1,"
+SELECT pg_input_error_info('1,', 'circle');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("invalid input syntax for type circle: ""1,""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
@@ -5314,9 +5314,9 @@ SELECT pg_input_is_valid('(1,2),-1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,2),-1', 'circle');
-              pg_input_error_message              
---------------------------------------------------
- invalid input syntax for type circle: "(1,2),-1"
+SELECT pg_input_error_info('(1,2),-1', 'circle');
+                      pg_input_error_info                       
+----------------------------------------------------------------
+ ("invalid input syntax for type circle: ""(1,2),-1""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index c9f466ac1d..ada484642a 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1063,10 +1063,10 @@ SELECT pg_input_is_valid('1234', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'cidr');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type cidr: "1234"
+SELECT pg_input_error_info('1234', 'cidr');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("invalid input syntax for type cidr: ""1234""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
@@ -1075,10 +1075,10 @@ SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
-          pg_input_error_message          
-------------------------------------------
- invalid cidr value: "192.168.198.200/24"
+SELECT pg_input_error_info('192.168.198.200/24', 'cidr');
+                                     pg_input_error_info                                      
+----------------------------------------------------------------------------------------------
+ ("invalid cidr value: ""192.168.198.200/24""","Value has bits set to right of mask.",,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('1234', 'inet');
@@ -1087,9 +1087,9 @@ SELECT pg_input_is_valid('1234', 'inet');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'inet');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type inet: "1234"
+SELECT pg_input_error_info('1234', 'inet');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("invalid input syntax for type inet: ""1234""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 73b4ee023c..c0b06a1aa4 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('50000', 'int2');
  f
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT pg_input_error_info('50000', 'int2');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 -- While we're here, check int2vector as well
@@ -77,16 +77,16 @@ SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
  t
 (1 row)
 
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-             pg_input_error_message             
-------------------------------------------------
- invalid input syntax for type smallint: "asdf"
+SELECT pg_input_error_info('1 asdf', 'int2vector');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("invalid input syntax for type smallint: ""asdf""",,,22P02)
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2vector');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT pg_input_error_info('50000', 'int2vector');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("value ""50000"" is out of range for type smallint",,,22003)
 (1 row)
 
 SELECT * FROM INT2_TBL AS f(a, b);
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 9c20574ca5..f0c469d8ab 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('1000000000000', 'int4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1000000000000', 'int4');
-                 pg_input_error_message                 
---------------------------------------------------------
- value "1000000000000" is out of range for type integer
+SELECT pg_input_error_info('1000000000000', 'int4');
+                         pg_input_error_info                          
+----------------------------------------------------------------------
+ ("value ""1000000000000"" is out of range for type integer",,,22003)
 (1 row)
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index d9dca64e88..7a788a15d7 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('10000000000000000000', 'int8');
  f
 (1 row)
 
-SELECT pg_input_error_message('10000000000000000000', 'int8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "10000000000000000000" is out of range for type bigint
+SELECT pg_input_error_info('10000000000000000000', 'int8');
+                            pg_input_error_info                             
+----------------------------------------------------------------------------
+ ("value ""10000000000000000000"" is out of range for type bigint",,,22003)
 (1 row)
 
 -- int8/int8 cmp
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a154840c85..7b654e77b2 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -91,16 +91,16 @@ SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'interval');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type interval: "garbage"
+SELECT pg_input_error_info('garbage', 'interval');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("invalid input syntax for type interval: ""garbage""",,,22007)
 (1 row)
 
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type interval: "@ 30 eons ago"
+SELECT pg_input_error_info('@ 30 eons ago', 'interval');
+                          pg_input_error_info                          
+-----------------------------------------------------------------------
+ ("invalid input syntax for type interval: ""@ 30 eons ago""",,,22007)
 (1 row)
 
 -- test interval operators
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index af96ce4180..7d574c25af 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -333,10 +333,10 @@ select pg_input_is_valid('{"a":true', 'json');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'json');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select pg_input_error_info('{"a":true', 'json');
+                                 pg_input_error_info                                  
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
 --constructors
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
index 083621fb21..21b0d11787 100644
--- a/src/test/regress/expected/json_encoding.out
+++ b/src/test/regress/expected/json_encoding.out
@@ -261,9 +261,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
- pg_input_error_message 
-------------------------
- 
+select pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+ pg_input_error_info 
+---------------------
+ (,,,)
 (1 row)
 
diff --git a/src/test/regress/expected/json_encoding_1.out b/src/test/regress/expected/json_encoding_1.out
index 021d226f8d..39d439e684 100644
--- a/src/test/regress/expected/json_encoding_1.out
+++ b/src/test/regress/expected/json_encoding_1.out
@@ -257,9 +257,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
-       pg_input_error_message        
--------------------------------------
- unsupported Unicode escape sequence
+select pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+                                                        pg_input_error_info                                                        
+-----------------------------------------------------------------------------------------------------------------------------------
+ ("unsupported Unicode escape sequence","Unicode escape value could not be translated to the server's encoding SQL_ASCII.",,22P05)
 (1 row)
 
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index d3248aa0fd..cfda43589e 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -323,16 +323,16 @@ select pg_input_is_valid('{"a":true', 'jsonb');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'jsonb');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select pg_input_error_info('{"a":true', 'jsonb');
+                                 pg_input_error_info                                  
+--------------------------------------------------------------------------------------
+ ("invalid input syntax for type json","The input string ended unexpectedly.",,22P02)
 (1 row)
 
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+select pg_input_error_info('{"a":1e1000000}', 'jsonb');
+            pg_input_error_info             
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 -- make sure jsonb is passed through json generators without being escaped
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index ca0cdf1ab2..eba11d485f 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -1035,18 +1035,18 @@ select '1?(2>3)'::jsonpath;
 -- test non-error-throwing API
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       pg_input_error_info(str,'jsonpath') as errmsg
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
                   '00',
                   '1a']) str;
-                 jsonpath                  | ok |                                errmsg                                 
--------------------------------------------+----+-----------------------------------------------------------------------
- $ ? (@ like_regex "pattern" flag "smixq") | t  | 
- $ ? (@ like_regex "pattern" flag "a")     | f  | invalid input syntax for type jsonpath
- @ + 1                                     | f  | @ is not allowed in root expressions
- 00                                        | f  | trailing junk after numeric literal at or near "00" of jsonpath input
- 1a                                        | f  | trailing junk after numeric literal at or near "1a" of jsonpath input
+                 jsonpath                  | ok |                                                     errmsg                                                     
+-------------------------------------------+----+----------------------------------------------------------------------------------------------------------------
+ $ ? (@ like_regex "pattern" flag "smixq") | t  | (,,,)
+ $ ? (@ like_regex "pattern" flag "a")     | f  | ("invalid input syntax for type jsonpath","Unrecognized flag character ""a"" in LIKE_REGEX predicate.",,42601)
+ @ + 1                                     | f  | ("@ is not allowed in root expressions",,,42601)
+ 00                                        | f  | ("trailing junk after numeric literal at or near ""00"" of jsonpath input",,,42601)
+ 1a                                        | f  | ("trailing junk after numeric literal at or near ""1a"" of jsonpath input",,,42601)
 (5 rows)
 
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index 6baea8fdbd..5682e49c4f 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -92,10 +92,10 @@ SELECT pg_input_is_valid('{1, 1}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1}', 'line');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type line: "{1, 1}"
+SELECT pg_input_error_info('{1, 1}', 'line');
+                    pg_input_error_info                     
+------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
@@ -104,10 +104,10 @@ SELECT pg_input_is_valid('{0, 0, 0}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid line specification: A and B cannot both be zero
+SELECT pg_input_error_info('{0, 0, 0}', 'line');
+                         pg_input_error_info                         
+---------------------------------------------------------------------
+ ("invalid line specification: A and B cannot both be zero",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
@@ -116,10 +116,10 @@ SELECT pg_input_is_valid('{1, 1, a}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, a}', 'line');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type line: "{1, 1, a}"
+SELECT pg_input_error_info('{1, 1, a}', 'line');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("invalid input syntax for type line: ""{1, 1, a}""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
@@ -128,10 +128,10 @@ SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT pg_input_error_info('{1, 1, 1e400}', 'line');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
@@ -140,9 +140,9 @@ SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT pg_input_error_info('(1, 1), (1, 1e400)', 'line');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index afb323fe04..ffefbfb507 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -49,9 +49,9 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type lseg: "[(1,2),(3)]"
+SELECT pg_input_error_info('[(1,2),(3)]', 'lseg');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("invalid input syntax for type lseg: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index cb646af79b..7ebc9da757 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -165,10 +165,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
-                   pg_input_error_message                   
-------------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+SELECT pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
+                           pg_input_error_info                            
+--------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
@@ -177,9 +177,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:"
+SELECT pg_input_error_info('08:00:2b:01:02:', 'macaddr');
+                          pg_input_error_info                           
+------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr: ""08:00:2b:01:02:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index bf681988f8..b047eafade 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -359,10 +359,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+SELECT pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+                               pg_input_error_info                               
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:ZZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
@@ -371,9 +371,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+SELECT pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
+                              pg_input_error_info                              
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type macaddr8: ""08:00:2b:01:02:03:04:""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 46b2eab51a..b87106a0f8 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -338,10 +338,10 @@ SELECT pg_input_is_valid('\x0001', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('\x0001', 'money');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type money: "\x0001"
+SELECT pg_input_error_info('\x0001', 'money');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("invalid input syntax for type money: ""\\x0001""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
@@ -350,10 +350,10 @@ SELECT pg_input_is_valid('192233720368547758.07', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('192233720368547758.07', 'money');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "192233720368547758.07" is out of range for type money
+SELECT pg_input_error_info('192233720368547758.07', 'money');
+                            pg_input_error_info                             
+----------------------------------------------------------------------------
+ ("value ""192233720368547758.07"" is out of range for type money",,,22003)
 (1 row)
 
 -- documented minimums and maximums
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index e70896b754..64b8d5fdda 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -287,10 +287,10 @@ select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
-            pg_input_error_message             
------------------------------------------------
- malformed multirange literal: "{[1,2], [4,5]"
+select pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
+                                  pg_input_error_info                                  
+---------------------------------------------------------------------------------------
+ ("malformed multirange literal: ""{[1,2], [4,5]""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
@@ -299,10 +299,10 @@ select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
+                    pg_input_error_info                     
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 56a3f3630a..f9c8334ecc 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2312,10 +2312,10 @@ SELECT pg_input_is_valid('1e400000', 'numeric');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400000', 'numeric');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+SELECT pg_input_error_info('1e400000', 'numeric');
+            pg_input_error_info             
+--------------------------------------------
+ ("value overflows numeric format",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
@@ -2330,16 +2330,16 @@ SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
- pg_input_error_message 
-------------------------
- numeric field overflow
+SELECT pg_input_error_info('1234.567', 'numeric(7,4)');
+                                                  pg_input_error_info                                                  
+-----------------------------------------------------------------------------------------------------------------------
+ ("numeric field overflow","A field with precision 7, scale 4 must round to an absolute value less than 10^3.",,22003)
 (1 row)
 
-SELECT pg_input_error_message('0x1234.567', 'numeric');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type numeric: "0x1234.567"
+SELECT pg_input_error_info('0x1234.567', 'numeric');
+                        pg_input_error_info                        
+-------------------------------------------------------------------
+ ("invalid input syntax for type numeric: ""0x1234.567""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/oid.out b/src/test/regress/expected/oid.out
index b664bab5f9..574e07c0fc 100644
--- a/src/test/regress/expected/oid.out
+++ b/src/test/regress/expected/oid.out
@@ -78,10 +78,10 @@ SELECT pg_input_is_valid('01XYZ', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('01XYZ', 'oid');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type oid: "01XYZ"
+SELECT pg_input_error_info('01XYZ', 'oid');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("invalid input syntax for type oid: ""01XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('9999999999', 'oid');
@@ -90,10 +90,10 @@ SELECT pg_input_is_valid('9999999999', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('9999999999', 'oid');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT pg_input_error_info('9999999999', 'oid');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 -- While we're here, check oidvector as well
@@ -109,10 +109,10 @@ SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type oid: "XYZ"
+SELECT pg_input_error_info('01 01XYZ', 'oidvector');
+                  pg_input_error_info                   
+--------------------------------------------------------
+ ("invalid input syntax for type oid: ""XYZ""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
@@ -121,10 +121,10 @@ SELECT pg_input_is_valid('01 9999999999', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT pg_input_error_info('01 9999999999', 'oidvector');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("value ""9999999999"" is out of range for type oid",,,22003)
 (1 row)
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 529a5e6fc2..92e6469946 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type path: "[(1,2),(3)]"
+SELECT pg_input_error_info('[(1,2),(3)]', 'path');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2),(3)]""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
@@ -99,9 +99,9 @@ SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type path: "[(1,2,6),(3,4,6)]"
+SELECT pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
+                          pg_input_error_info                          
+-----------------------------------------------------------------------
+ ("invalid input syntax for type path: ""[(1,2,6),(3,4,6)]""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out
index 01501f8c9b..cbbdc9a1d7 100644
--- a/src/test/regress/expected/pg_lsn.out
+++ b/src/test/regress/expected/pg_lsn.out
@@ -33,10 +33,10 @@ SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
  f
 (1 row)
 
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type pg_lsn: "16AE7F7"
+SELECT pg_input_error_info('16AE7F7', 'pg_lsn');
+                      pg_input_error_info                      
+---------------------------------------------------------------
+ ("invalid input syntax for type pg_lsn: ""16AE7F7""",,,22P02)
 (1 row)
 
 -- Min/Max aggregation
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index a716ceb881..76d053cc27 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -470,9 +470,9 @@ SELECT pg_input_is_valid('1,y', 'point');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,y', 'point');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type point: "1,y"
+SELECT pg_input_error_info('1,y', 'point');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("invalid input syntax for type point: ""1,y""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index c7d565ad53..22b972f907 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -313,10 +313,10 @@ SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type polygon: "(2.0,0.8,0.1)"
+SELECT pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
+                         pg_input_error_info                          
+----------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,0.8,0.1)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
@@ -325,9 +325,9 @@ SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type polygon: "(2.0,xyz)"
+SELECT pg_input_error_info('(2.0,xyz)', 'polygon');
+                       pg_input_error_info                        
+------------------------------------------------------------------
+ ("invalid input syntax for type polygon: ""(2.0,xyz)""",,,22P02)
 (1 row)
 
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 95d1e5515f..1a91ee123f 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2246,10 +2246,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
-     pg_input_error_message      
----------------------------------
- a name must follow the "/" sign
+SELECT pg_input_error_info('regress_priv_user1=r/', 'aclitem');
+              pg_input_error_info              
+-----------------------------------------------
+ ("a name must follow the ""/"" sign",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
@@ -2258,10 +2258,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem')
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-           pg_input_error_message           
---------------------------------------------
- role "regress_no_such_user" does not exist
+SELECT pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("role ""regress_no_such_user"" does not exist",,,42704)
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
@@ -2270,10 +2270,10 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm"
+SELECT pg_input_error_info('regress_priv_user1=rY', 'aclitem');
+                          pg_input_error_info                           
+------------------------------------------------------------------------
+ ("invalid mode character: must be one of ""arwdDxtXUCTcsAm""",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a3e9e447af..0571e72534 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -188,10 +188,10 @@ select pg_input_is_valid('(1,4', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(1,4', 'int4range');
-     pg_input_error_message      
----------------------------------
- malformed range literal: "(1,4"
+select pg_input_error_info('(1,4', 'int4range');
+                           pg_input_error_info                           
+-------------------------------------------------------------------------
+ ("malformed range literal: ""(1,4""","Unexpected end of input.",,22P02)
 (1 row)
 
 select pg_input_is_valid('(4,1)', 'int4range');
@@ -200,10 +200,10 @@ select pg_input_is_valid('(4,1)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,1)', 'int4range');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- range lower bound must be less than or equal to range upper bound
+select pg_input_error_info('(4,1)', 'int4range');
+                              pg_input_error_info                              
+-------------------------------------------------------------------------------
+ ("range lower bound must be less than or equal to range upper bound",,,22000)
 (1 row)
 
 select pg_input_is_valid('(4,zed)', 'int4range');
@@ -212,10 +212,10 @@ select pg_input_is_valid('(4,zed)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,zed)', 'int4range');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select pg_input_error_info('(4,zed)', 'int4range');
+                    pg_input_error_info                     
+------------------------------------------------------------
+ ("invalid input syntax for type integer: ""zed""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('[1,2147483647]', 'int4range');
@@ -224,10 +224,10 @@ select pg_input_is_valid('[1,2147483647]', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('[1,2147483647]', 'int4range');
- pg_input_error_message 
-------------------------
- integer out of range
+select pg_input_error_info('[1,2147483647]', 'int4range');
+       pg_input_error_info        
+----------------------------------
+ ("integer out of range",,,22003)
 (1 row)
 
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
@@ -236,10 +236,10 @@ select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
  f
 (1 row)
 
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
- pg_input_error_message 
-------------------------
- date out of range
+select pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
+      pg_input_error_info      
+-------------------------------
+ ("date out of range",,,22008)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..13e3b7eda9 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -448,10 +448,10 @@ SELECT to_regnamespace('foo.bar');
 (1 row)
 
 -- Test soft-error API
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
-            pg_input_error_message             
------------------------------------------------
- relation "ng_catalog.pg_class" does not exist
+SELECT pg_input_error_info('ng_catalog.pg_class', 'regclass');
+                     pg_input_error_info                     
+-------------------------------------------------------------
+ ("relation ""ng_catalog.pg_class"" does not exist",,,42P01)
 (1 row)
 
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
@@ -460,87 +460,87 @@ SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
  f
 (1 row)
 
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-                  pg_input_error_message                   
------------------------------------------------------------
- text search configuration "no_such_config" does not exist
+SELECT pg_input_error_info('no_such_config', 'regconfig');
+                           pg_input_error_info                           
+-------------------------------------------------------------------------
+ ("text search configuration ""no_such_config"" does not exist",,,42704)
 (1 row)
 
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-                   pg_input_error_message                   
-------------------------------------------------------------
- text search dictionary "no_such_dictionary" does not exist
+SELECT pg_input_error_info('no_such_dictionary', 'regdictionary');
+                           pg_input_error_info                            
+--------------------------------------------------------------------------
+ ("text search dictionary ""no_such_dictionary"" does not exist",,,42704)
 (1 row)
 
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-       pg_input_error_message        
--------------------------------------
- schema "nonexistent" does not exist
+SELECT pg_input_error_info('Nonexistent', 'regnamespace');
+                pg_input_error_info                
+---------------------------------------------------
+ ("schema ""nonexistent"" does not exist",,,3F000)
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-         pg_input_error_message          
------------------------------------------
- operator does not exist: ng_catalog.||/
+SELECT pg_input_error_info('ng_catalog.||/', 'regoper');
+                 pg_input_error_info                 
+-----------------------------------------------------
+ ("operator does not exist: ng_catalog.||/",,,42883)
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoper');
-     pg_input_error_message     
---------------------------------
- more than one operator named -
+SELECT pg_input_error_info('-', 'regoper');
+            pg_input_error_info             
+--------------------------------------------
+ ("more than one operator named -",,,42725)
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-              pg_input_error_message              
---------------------------------------------------
- operator does not exist: ng_catalog.+(int4,int4)
+SELECT pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("operator does not exist: ng_catalog.+(int4,int4)",,,42883)
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoperator');
-   pg_input_error_message    
------------------------------
- expected a left parenthesis
+SELECT pg_input_error_info('-', 'regoperator');
+           pg_input_error_info           
+-----------------------------------------
+ ("expected a left parenthesis",,,22P02)
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-          pg_input_error_message          
-------------------------------------------
- function "ng_catalog.now" does not exist
+SELECT pg_input_error_info('ng_catalog.now', 'regproc');
+                  pg_input_error_info                   
+--------------------------------------------------------
+ ("function ""ng_catalog.now"" does not exist",,,42883)
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-              pg_input_error_message               
----------------------------------------------------
- function "ng_catalog.abs(numeric)" does not exist
+SELECT pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("function ""ng_catalog.abs(numeric)"" does not exist",,,42883)
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-    pg_input_error_message    
-------------------------------
- expected a right parenthesis
+SELECT pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+           pg_input_error_info            
+------------------------------------------
+ ("expected a right parenthesis",,,22P02)
 (1 row)
 
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-           pg_input_error_message           
---------------------------------------------
- role "regress_regrole_test" does not exist
+SELECT pg_input_error_info('regress_regrole_test', 'regrole');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("role ""regress_regrole_test"" does not exist",,,42704)
 (1 row)
 
-SELECT pg_input_error_message('no_such_type', 'regtype');
-       pg_input_error_message       
-------------------------------------
- type "no_such_type" does not exist
+SELECT pg_input_error_info('no_such_type', 'regtype');
+               pg_input_error_info                
+--------------------------------------------------
+ ("type ""no_such_type"" does not exist",,,42704)
 (1 row)
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
+SELECT pg_input_error_info('incorrect type name syntax', 'regtype');
 ERROR:  syntax error at or near "type"
-LINE 1: SELECT pg_input_error_message('incorrect type name syntax', ...
+LINE 1: SELECT pg_input_error_info('incorrect type name syntax', 're...
                   ^
 CONTEXT:  invalid type name "incorrect type name syntax"
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
 ERROR:  invalid NUMERIC type modifier
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
+SELECT pg_input_error_info('way.too.many.names', 'regtype');
 ERROR:  improper qualified name (too many dotted names): way.too.many.names
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT pg_input_error_info('no_such_catalog.schema.name', 'regtype');
 ERROR:  cross-database references are not implemented: no_such_catalog.schema.name
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 801d9e556b..f00453c31f 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -88,16 +88,16 @@ SELECT pg_input_is_valid('(1,zed)', 'complex');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,zed)', 'complex');
-                pg_input_error_message                 
--------------------------------------------------------
- invalid input syntax for type double precision: "zed"
+SELECT pg_input_error_info('(1,zed)', 'complex');
+                         pg_input_error_info                         
+---------------------------------------------------------------------
+ ("invalid input syntax for type double precision: ""zed""",,,22P02)
 (1 row)
 
-SELECT pg_input_error_message('(1,1e400)', 'complex');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT pg_input_error_info('(1,1e400)', 'complex');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("""1e400"" is out of range for type double precision",,,22003)
 (1 row)
 
 create temp table quadtable(f1 int, q quad);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index f028c1f10f..d6046de7bc 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -280,22 +280,22 @@ SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
  f
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-             pg_input_error_message             
-------------------------------------------------
- invalid hexadecimal data: odd number of digits
+SELECT pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+                    pg_input_error_info                     
+------------------------------------------------------------
+ ("invalid hexadecimal data: odd number of digits",,,22023)
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-     pg_input_error_message     
---------------------------------
- invalid hexadecimal digit: "x"
+SELECT pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+             pg_input_error_info              
+----------------------------------------------
+ ("invalid hexadecimal digit: ""x""",,,22023)
 (1 row)
 
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
-       pg_input_error_message        
--------------------------------------
- invalid input syntax for type bytea
+SELECT pg_input_error_info(E'foo\\99bar', 'bytea');
+               pg_input_error_info               
+-------------------------------------------------
+ ("invalid input syntax for type bytea",,,22P02)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out
index ff67ed43f0..bd9a57910f 100644
--- a/src/test/regress/expected/tid.out
+++ b/src/test/regress/expected/tid.out
@@ -24,10 +24,10 @@ SELECT pg_input_is_valid('(0)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0)', 'tid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type tid: "(0)"
+SELECT pg_input_error_info('(0)', 'tid');
+                  pg_input_error_info                   
+--------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0)""",,,22P02)
 (1 row)
 
 SELECT pg_input_is_valid('(0,-1)', 'tid');
@@ -36,10 +36,10 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0,-1)', 'tid');
-           pg_input_error_message            
----------------------------------------------
- invalid input syntax for type tid: "(0,-1)"
+SELECT pg_input_error_info('(0,-1)', 'tid');
+                    pg_input_error_info                    
+-----------------------------------------------------------
+ ("invalid input syntax for type tid: ""(0,-1)""",,,22P02)
 (1 row)
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index a44caededd..d982d591e1 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -133,16 +133,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00', 'time');
-             pg_input_error_message             
-------------------------------------------------
- date/time field value out of range: "25:00:00"
+SELECT pg_input_error_info('25:00:00', 'time');
+                     pg_input_error_info                      
+--------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00""",,,22008)
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type time: "15:36:39 America/New_York"
+SELECT pg_input_error_info('15:36:39 America/New_York', 'time');
+                              pg_input_error_info                              
+-------------------------------------------------------------------------------
+ ("invalid input syntax for type time: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index eef2f7001c..7efa86d509 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -144,16 +144,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamp');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type timestamp: "garbage"
+SELECT pg_input_error_info('garbage', 'timestamp');
+                       pg_input_error_info                        
+------------------------------------------------------------------
+ ("invalid input syntax for type timestamp: ""garbage""",,,22007)
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index b85a93a3c2..6e9c4152f4 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -195,16 +195,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamptz');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type timestamp with time zone: "garbage"
+SELECT pg_input_error_info('garbage', 'timestamptz');
+                               pg_input_error_info                               
+---------------------------------------------------------------------------------
+ ("invalid input syntax for type timestamp with time zone: ""garbage""",,,22007)
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("time zone ""nehwon/lankhmar"" not recognized",,,22023)
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 984285663b..8e8fd215f4 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -150,16 +150,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-               pg_input_error_message               
-----------------------------------------------------
- date/time field value out of range: "25:00:00 PDT"
+SELECT pg_input_error_info('25:00:00 PDT', 'timetz');
+                       pg_input_error_info                        
+------------------------------------------------------------------
+ ("date/time field value out of range: ""25:00:00 PDT""",,,22008)
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
-                             pg_input_error_message                             
---------------------------------------------------------------------------------
- invalid input syntax for type time with time zone: "15:36:39 America/New_York"
+SELECT pg_input_error_info('15:36:39 America/New_York', 'timetz');
+                                     pg_input_error_info                                      
+----------------------------------------------------------------------------------------------
+ ("invalid input syntax for type time with time zone: ""15:36:39 America/New_York""",,,22007)
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index a8785cd708..ee885872d3 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -102,10 +102,10 @@ SELECT pg_input_is_valid($$''$$, 'tsvector');
  f
 (1 row)
 
-SELECT pg_input_error_message($$''$$, 'tsvector');
-     pg_input_error_message     
---------------------------------
- syntax error in tsvector: "''"
+SELECT pg_input_error_info($$''$$, 'tsvector');
+             pg_input_error_info              
+----------------------------------------------
+ ("syntax error in tsvector: ""''""",,,42601)
 (1 row)
 
 --Base tsquery test
@@ -404,16 +404,16 @@ SELECT pg_input_is_valid('foo!', 'tsquery');
  f
 (1 row)
 
-SELECT pg_input_error_message('foo!', 'tsquery');
-     pg_input_error_message      
----------------------------------
- syntax error in tsquery: "foo!"
+SELECT pg_input_error_info('foo!', 'tsquery');
+              pg_input_error_info              
+-----------------------------------------------
+ ("syntax error in tsquery: ""foo!""",,,42601)
 (1 row)
 
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
-                                pg_input_error_message                                 
----------------------------------------------------------------------------------------
- distance in phrase operator must be an integer value between zero and 16384 inclusive
+SELECT pg_input_error_info('a <100000> b', 'tsquery');
+                                        pg_input_error_info                                        
+---------------------------------------------------------------------------------------------------
+ ("distance in phrase operator must be an integer value between zero and 16384 inclusive",,,22023)
 (1 row)
 
 --comparisons
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 0f47232009..7cfbd45b86 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -46,10 +46,10 @@ SELECT pg_input_is_valid('11', 'uuid');
  f
 (1 row)
 
-SELECT pg_input_error_message('11', 'uuid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type uuid: "11"
+SELECT pg_input_error_info('11', 'uuid');
+                  pg_input_error_info                   
+--------------------------------------------------------
+ ("invalid input syntax for type uuid: ""11""",,,22P02)
 (1 row)
 
 --inserting three input formats
diff --git a/src/test/regress/expected/varchar.out b/src/test/regress/expected/varchar.out
index 62b683d86f..96ce47490d 100644
--- a/src/test/regress/expected/varchar.out
+++ b/src/test/regress/expected/varchar.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT pg_input_error_info('abcde', 'varchar(4)');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_1.out b/src/test/regress/expected/varchar_1.out
index 6690f81c0b..d65a4d80df 100644
--- a/src/test/regress/expected/varchar_1.out
+++ b/src/test/regress/expected/varchar_1.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT pg_input_error_info('abcde', 'varchar(4)');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_2.out b/src/test/regress/expected/varchar_2.out
index ad8aa7c693..14f7655239 100644
--- a/src/test/regress/expected/varchar_2.out
+++ b/src/test/regress/expected/varchar_2.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT pg_input_error_info('abcde', 'varchar(4)');
+                   pg_input_error_info                    
+----------------------------------------------------------
+ ("value too long for type character varying(4)",,,22001)
 (1 row)
 
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index e62f701943..ddda75e57e 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -43,10 +43,10 @@ SELECT pg_input_is_valid('asdf', 'xid');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffff', 'xid');
-              pg_input_error_message               
----------------------------------------------------
- value "0xffffffffff" is out of range for type xid
+SELECT pg_input_error_info('0xffffffffff', 'xid');
+                       pg_input_error_info                       
+-----------------------------------------------------------------
+ ("value ""0xffffffffff"" is out of range for type xid",,,22003)
 (1 row)
 
 SELECT pg_input_is_valid('42', 'xid8');
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('asdf', 'xid8');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "0xffffffffffffffffffff" is out of range for type xid8
+SELECT pg_input_error_info('0xffffffffffffffffffff', 'xid8');
+                            pg_input_error_info                             
+----------------------------------------------------------------------------
+ ("value ""0xffffffffffffffffffff"" is out of range for type xid8",,,22003)
 (1 row)
 
 -- equality
@@ -223,10 +223,10 @@ select pg_input_is_valid('31:12:', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('31:12:', 'pg_snapshot');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type pg_snapshot: "31:12:"
+select pg_input_error_info('31:12:', 'pg_snapshot');
+                        pg_input_error_info                        
+-------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""31:12:""",,,22P02)
 (1 row)
 
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
@@ -235,10 +235,10 @@ select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type pg_snapshot: "12:16:14,13"
+select pg_input_error_info('12:16:14,13', 'pg_snapshot');
+                          pg_input_error_info                           
+------------------------------------------------------------------------
+ ("invalid input syntax for type pg_snapshot: ""12:16:14,13""",,,22P02)
 (1 row)
 
 create temp table snapshot_test (
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..ad852dc2f7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -31,9 +31,9 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
-------------------------
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message       
+---------------------
  invalid XML content
 (1 row)
 
@@ -43,8 +43,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 378b412db0..70fe34a04f 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -29,13 +29,13 @@ DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlcomment('test');
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 42055c5003..e01f431219 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -29,8 +29,8 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message          
 ------------------------
  invalid XML content
 (1 row)
@@ -41,8 +41,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 38e8dd440b..954c1225b4 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -117,7 +117,7 @@ SELECT a,b,c FROM arrtest;
 SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
 SELECT pg_input_is_valid('{1,2', 'integer[]');
 SELECT pg_input_is_valid('{1,zed}', 'integer[]');
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
+SELECT pg_input_error_info('{1,zed}', 'integer[]');
 
 -- test mixed slice/scalar subscripting
 select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 8814249c2a..5765ee8672 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -232,13 +232,13 @@ TABLE bit_defaults;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('01010001', 'bit(10)');
-SELECT pg_input_error_message('01010001', 'bit(10)');
+SELECT pg_input_error_info('01010001', 'bit(10)');
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
+SELECT pg_input_error_info('01010Z01', 'bit(8)');
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
+SELECT pg_input_error_info('x01010Z01', 'bit(32)');
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
-SELECT pg_input_error_message('01010Z01', 'varbit');
+SELECT pg_input_error_info('01010Z01', 'varbit');
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
-SELECT pg_input_error_message('x01010Z01', 'varbit');
+SELECT pg_input_error_info('x01010Z01', 'varbit');
diff --git a/src/test/regress/sql/boolean.sql b/src/test/regress/sql/boolean.sql
index dfaa55dd0f..9126831dba 100644
--- a/src/test/regress/sql/boolean.sql
+++ b/src/test/regress/sql/boolean.sql
@@ -65,7 +65,7 @@ SELECT bool '' AS error;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('true', 'bool');
 SELECT pg_input_is_valid('asdf', 'bool');
-SELECT pg_input_error_message('junk', 'bool');
+SELECT pg_input_error_info('junk', 'bool');
 
 -- and, or, not in qualifications
 
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 02e100391b..cbf967f3ae 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -284,6 +284,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('200', 'box');
-SELECT pg_input_error_message('200', 'box');
+SELECT pg_input_error_info('200', 'box');
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
+SELECT pg_input_error_info('((200,300),(500, xyz))', 'box');
diff --git a/src/test/regress/sql/char.sql b/src/test/regress/sql/char.sql
index 8aa43b0fb8..f8e3304053 100644
--- a/src/test/regress/sql/char.sql
+++ b/src/test/regress/sql/char.sql
@@ -75,7 +75,7 @@ SELECT * FROM CHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'char(4)');
 SELECT pg_input_is_valid('abcde', 'char(4)');
-SELECT pg_input_error_message('abcde', 'char(4)');
+SELECT pg_input_error_info('abcde', 'char(4)');
 
 --
 -- Also test "char", which is an ad-hoc one-byte type.  It can only
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql
index 89982dd2f8..8ced2c9bc5 100644
--- a/src/test/regress/sql/date.sql
+++ b/src/test/regress/sql/date.sql
@@ -197,8 +197,8 @@ SELECT date '5874898-01-01';  -- out of range
 SELECT pg_input_is_valid('now', 'date');
 SELECT pg_input_is_valid('garbage', 'date');
 SELECT pg_input_is_valid('6874898-01-01', 'date');
-SELECT pg_input_error_message('garbage', 'date');
-SELECT pg_input_error_message('6874898-01-01', 'date');
+SELECT pg_input_error_info('garbage', 'date');
+SELECT pg_input_error_info('6874898-01-01', 'date');
 
 RESET datestyle;
 
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 1558bd9a33..8ee0170369 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -77,12 +77,12 @@ create domain weirdfloat float8 check((1 / value) < 10);
 select pg_input_is_valid('1', 'positiveint');
 select pg_input_is_valid('junk', 'positiveint');
 select pg_input_is_valid('-1', 'positiveint');
-select pg_input_error_message('junk', 'positiveint');
-select pg_input_error_message('-1', 'positiveint');
-select pg_input_error_message('junk', 'weirdfloat');
-select pg_input_error_message('0.01', 'weirdfloat');
+select pg_input_error_info('junk', 'positiveint');
+select pg_input_error_info('-1', 'positiveint');
+select pg_input_error_info('junk', 'weirdfloat');
+select pg_input_error_info('0.01', 'weirdfloat');
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select pg_input_error_info('0', 'weirdfloat');
 
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index c87656589b..417fa6eddd 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -18,8 +18,8 @@ SELECT 'mauve'::rainbow;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('red', 'rainbow');
 SELECT pg_input_is_valid('mauve', 'rainbow');
-SELECT pg_input_error_message('mauve', 'rainbow');
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
+SELECT pg_input_error_info('mauve', 'rainbow');
+SELECT pg_input_error_info(repeat('too_long', 32), 'rainbow');
 
 --
 -- adding new values
diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4.sql
index 061477726b..4f344997e9 100644
--- a/src/test/regress/sql/float4.sql
+++ b/src/test/regress/sql/float4.sql
@@ -40,7 +40,7 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
 SELECT pg_input_is_valid('34.5', 'float4');
 SELECT pg_input_is_valid('xyz', 'float4');
 SELECT pg_input_is_valid('1e400', 'float4');
-SELECT pg_input_error_message('1e400', 'float4');
+SELECT pg_input_error_info('1e400', 'float4');
 
 -- special inputs
 SELECT 'NaN'::float4;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index c276a5324c..d5fd409580 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -38,7 +38,7 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123           5');
 SELECT pg_input_is_valid('34.5', 'float8');
 SELECT pg_input_is_valid('xyz', 'float8');
 SELECT pg_input_is_valid('1e4000', 'float8');
-SELECT pg_input_error_message('1e4000', 'float8');
+SELECT pg_input_error_info('1e4000', 'float8');
 
 -- special inputs
 SELECT 'NaN'::float8;
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 309234b76c..70576ab7ff 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -526,6 +526,6 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(1', 'circle');
-SELECT pg_input_error_message('1,', 'circle');
+SELECT pg_input_error_info('1,', 'circle');
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
-SELECT pg_input_error_message('(1,2),-1', 'circle');
+SELECT pg_input_error_info('(1,2),-1', 'circle');
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index abfcd4242f..ae3f19d285 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -255,9 +255,9 @@ SELECT a FROM (VALUES
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1234', 'cidr');
-SELECT pg_input_error_message('1234', 'cidr');
+SELECT pg_input_error_info('1234', 'cidr');
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
+SELECT pg_input_error_info('192.168.198.200/24', 'cidr');
 
 SELECT pg_input_is_valid('1234', 'inet');
-SELECT pg_input_error_message('1234', 'inet');
+SELECT pg_input_error_info('1234', 'inet');
diff --git a/src/test/regress/sql/int2.sql b/src/test/regress/sql/int2.sql
index ce8ac97963..7da875c402 100644
--- a/src/test/regress/sql/int2.sql
+++ b/src/test/regress/sql/int2.sql
@@ -21,12 +21,12 @@ SELECT * FROM INT2_TBL;
 SELECT pg_input_is_valid('34', 'int2');
 SELECT pg_input_is_valid('asdf', 'int2');
 SELECT pg_input_is_valid('50000', 'int2');
-SELECT pg_input_error_message('50000', 'int2');
+SELECT pg_input_error_info('50000', 'int2');
 
 -- While we're here, check int2vector as well
 SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-SELECT pg_input_error_message('50000', 'int2vector');
+SELECT pg_input_error_info('1 asdf', 'int2vector');
+SELECT pg_input_error_info('50000', 'int2vector');
 
 SELECT * FROM INT2_TBL AS f(a, b);
 
diff --git a/src/test/regress/sql/int4.sql b/src/test/regress/sql/int4.sql
index 146963edfb..659d1ab939 100644
--- a/src/test/regress/sql/int4.sql
+++ b/src/test/regress/sql/int4.sql
@@ -21,7 +21,7 @@ SELECT * FROM INT4_TBL;
 SELECT pg_input_is_valid('34', 'int4');
 SELECT pg_input_is_valid('asdf', 'int4');
 SELECT pg_input_is_valid('1000000000000', 'int4');
-SELECT pg_input_error_message('1000000000000', 'int4');
+SELECT pg_input_error_info('1000000000000', 'int4');
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
 
diff --git a/src/test/regress/sql/int8.sql b/src/test/regress/sql/int8.sql
index c85717c072..14bc99bd5e 100644
--- a/src/test/regress/sql/int8.sql
+++ b/src/test/regress/sql/int8.sql
@@ -20,7 +20,7 @@ SELECT * FROM INT8_TBL;
 SELECT pg_input_is_valid('34', 'int8');
 SELECT pg_input_is_valid('asdf', 'int8');
 SELECT pg_input_is_valid('10000000000000000000', 'int8');
-SELECT pg_input_error_message('10000000000000000000', 'int8');
+SELECT pg_input_error_info('10000000000000000000', 'int8');
 
 -- int8/int8 cmp
 SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index af8e1ca0f4..171bbbf653 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -36,8 +36,8 @@ INSERT INTO INTERVAL_TBL (f1) VALUES ('@ 30 eons ago');
 SELECT pg_input_is_valid('1.5 weeks', 'interval');
 SELECT pg_input_is_valid('garbage', 'interval');
 SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
-SELECT pg_input_error_message('garbage', 'interval');
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
+SELECT pg_input_error_info('garbage', 'interval');
+SELECT pg_input_error_info('@ 30 eons ago', 'interval');
 
 -- test interval operators
 
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 21534ed959..68e4c9af8f 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -84,7 +84,7 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'json');
 select pg_input_is_valid('{"a":true', 'json');
-select pg_input_error_message('{"a":true', 'json');
+select pg_input_error_info('{"a":true', 'json');
 
 --constructors
 -- array_to_json
diff --git a/src/test/regress/sql/json_encoding.sql b/src/test/regress/sql/json_encoding.sql
index f87b3bd4f3..e7d11fd25b 100644
--- a/src/test/regress/sql/json_encoding.sql
+++ b/src/test/regress/sql/json_encoding.sql
@@ -79,4 +79,4 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 
 -- soft error for input-time failure
 
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+select pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 9f67f4c71d..651e9408ec 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -89,8 +89,8 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'jsonb');
 select pg_input_is_valid('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
+select pg_input_error_info('{"a":true', 'jsonb');
+select pg_input_error_info('{"a":1e1000000}', 'jsonb');
 
 -- make sure jsonb is passed through json generators without being escaped
 SELECT array_to_json(ARRAY [jsonb '{"a":1}', jsonb '{"b":[2,3]}']);
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 99d21d2af7..2fba9c1057 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -192,7 +192,7 @@ select '1?(2>3)'::jsonpath;
 
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       pg_input_error_info(str,'jsonpath') as errmsg
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index f706a41184..42b37138e9 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -43,12 +43,12 @@ select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('{1, 1}', 'line');
-SELECT pg_input_error_message('{1, 1}', 'line');
+SELECT pg_input_error_info('{1, 1}', 'line');
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
+SELECT pg_input_error_info('{0, 0, 0}', 'line');
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
-SELECT pg_input_error_message('{1, 1, a}', 'line');
+SELECT pg_input_error_info('{1, 1, a}', 'line');
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
+SELECT pg_input_error_info('{1, 1, 1e400}', 'line');
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
+SELECT pg_input_error_info('(1, 1), (1, 1e400)', 'line');
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 0fece162e0..095a798017 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -25,4 +25,4 @@ select * from LSEG_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
+SELECT pg_input_error_info('[(1,2),(3)]', 'lseg');
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index 211397c8f3..56a24cd88f 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -44,6 +44,6 @@ DROP TABLE macaddr_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
+SELECT pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
+SELECT pg_input_error_info('08:00:2b:01:02:', 'macaddr');
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
index b29f785b41..a796034cc5 100644
--- a/src/test/regress/sql/macaddr8.sql
+++ b/src/test/regress/sql/macaddr8.sql
@@ -90,6 +90,6 @@ DROP TABLE macaddr8_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+SELECT pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
+SELECT pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql
index cd9a089e01..073aa0a38b 100644
--- a/src/test/regress/sql/money.sql
+++ b/src/test/regress/sql/money.sql
@@ -90,9 +90,9 @@ SELECT '($123,456.78)'::money;
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('\x0001', 'money');
-SELECT pg_input_error_message('\x0001', 'money');
+SELECT pg_input_error_info('\x0001', 'money');
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
-SELECT pg_input_error_message('192233720368547758.07', 'money');
+SELECT pg_input_error_info('192233720368547758.07', 'money');
 
 -- documented minimums and maximums
 SELECT '-92233720368547758.08'::money;
diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql
index fc369a550c..724af7f8d3 100644
--- a/src/test/regress/sql/multirangetypes.sql
+++ b/src/test/regress/sql/multirangetypes.sql
@@ -61,9 +61,9 @@ select '{(a,a)}'::textmultirange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('{[1,2], [4,5]}', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
+select pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
+select pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
 
 --
 -- test the constructor
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 2db7656e84..4abc47a363 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1086,11 +1086,11 @@ SELECT * FROM num_input_test;
 SELECT pg_input_is_valid('34.5', 'numeric');
 SELECT pg_input_is_valid('34xyz', 'numeric');
 SELECT pg_input_is_valid('1e400000', 'numeric');
-SELECT pg_input_error_message('1e400000', 'numeric');
+SELECT pg_input_error_info('1e400000', 'numeric');
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
 SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('0x1234.567', 'numeric');
+SELECT pg_input_error_info('1234.567', 'numeric(7,4)');
+SELECT pg_input_error_info('0x1234.567', 'numeric');
 
 --
 -- Test precision and scale typemods
diff --git a/src/test/regress/sql/oid.sql b/src/test/regress/sql/oid.sql
index 39937c2f1d..e2bc32a8b6 100644
--- a/src/test/regress/sql/oid.sql
+++ b/src/test/regress/sql/oid.sql
@@ -31,16 +31,16 @@ SELECT * FROM OID_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('1234', 'oid');
 SELECT pg_input_is_valid('01XYZ', 'oid');
-SELECT pg_input_error_message('01XYZ', 'oid');
+SELECT pg_input_error_info('01XYZ', 'oid');
 SELECT pg_input_is_valid('9999999999', 'oid');
-SELECT pg_input_error_message('9999999999', 'oid');
+SELECT pg_input_error_info('9999999999', 'oid');
 
 -- While we're here, check oidvector as well
 SELECT pg_input_is_valid(' 1 2  4 ', 'oidvector');
 SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
+SELECT pg_input_error_info('01 01XYZ', 'oidvector');
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
+SELECT pg_input_error_info('01 9999999999', 'oidvector');
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
 
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 42c90afe53..3dad134bbb 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -45,6 +45,6 @@ SELECT popen(f1) AS open_path FROM PATH_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
+SELECT pg_input_error_info('[(1,2),(3)]', 'path');
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
+SELECT pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
diff --git a/src/test/regress/sql/pg_lsn.sql b/src/test/regress/sql/pg_lsn.sql
index 3d57d66e0c..7ba54b9c1b 100644
--- a/src/test/regress/sql/pg_lsn.sql
+++ b/src/test/regress/sql/pg_lsn.sql
@@ -17,7 +17,7 @@ INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
+SELECT pg_input_error_info('16AE7F7', 'pg_lsn');
 
 -- Min/Max aggregation
 SELECT MIN(f1), MAX(f1) FROM PG_LSN_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 7bd1ebe2b5..49c2e85de5 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -99,4 +99,4 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1,y', 'point');
-SELECT pg_input_error_message('1,y', 'point');
+SELECT pg_input_error_info('1,y', 'point');
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index da644e34e3..2ca1a5ac2b 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -143,6 +143,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
+SELECT pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
+SELECT pg_input_error_info('(2.0,xyz)', 'polygon');
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 0bcea77ff4..5db53b97ca 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -1433,11 +1433,11 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
 -- Test non-throwing aclitem I/O
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
+SELECT pg_input_error_info('regress_priv_user1=r/', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+SELECT pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
+SELECT pg_input_error_info('regress_priv_user1=rY', 'aclitem');
 
 --
 -- Testing blanket default grants is very hazardous since it might change
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index 4e6a0912de..4729a1c2d4 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -43,15 +43,15 @@ select '(a,a)'::textrange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('(1,4)', 'int4range');
 select pg_input_is_valid('(1,4', 'int4range');
-select pg_input_error_message('(1,4', 'int4range');
+select pg_input_error_info('(1,4', 'int4range');
 select pg_input_is_valid('(4,1)', 'int4range');
-select pg_input_error_message('(4,1)', 'int4range');
+select pg_input_error_info('(4,1)', 'int4range');
 select pg_input_is_valid('(4,zed)', 'int4range');
-select pg_input_error_message('(4,zed)', 'int4range');
+select pg_input_error_info('(4,zed)', 'int4range');
 select pg_input_is_valid('[1,2147483647]', 'int4range');
-select pg_input_error_message('[1,2147483647]', 'int4range');
+select pg_input_error_info('[1,2147483647]', 'int4range');
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
+select pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
 
 --
 -- create some test data and test the operators
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index 2cb8c9a253..e8c7394c5c 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -125,23 +125,23 @@ SELECT to_regnamespace('foo.bar');
 
 -- Test soft-error API
 
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
+SELECT pg_input_error_info('ng_catalog.pg_class', 'regclass');
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-SELECT pg_input_error_message('-', 'regoper');
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-SELECT pg_input_error_message('-', 'regoperator');
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-SELECT pg_input_error_message('no_such_type', 'regtype');
+SELECT pg_input_error_info('no_such_config', 'regconfig');
+SELECT pg_input_error_info('no_such_dictionary', 'regdictionary');
+SELECT pg_input_error_info('Nonexistent', 'regnamespace');
+SELECT pg_input_error_info('ng_catalog.||/', 'regoper');
+SELECT pg_input_error_info('-', 'regoper');
+SELECT pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+SELECT pg_input_error_info('-', 'regoperator');
+SELECT pg_input_error_info('ng_catalog.now', 'regproc');
+SELECT pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+SELECT pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+SELECT pg_input_error_info('regress_regrole_test', 'regrole');
+SELECT pg_input_error_info('no_such_type', 'regtype');
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT pg_input_error_info('incorrect type name syntax', 'regtype');
+SELECT pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT pg_input_error_info('way.too.many.names', 'regtype');
+SELECT pg_input_error_info('no_such_catalog.schema.name', 'regtype');
diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql
index 0844e7488d..951f0e60e2 100644
--- a/src/test/regress/sql/rowtypes.sql
+++ b/src/test/regress/sql/rowtypes.sql
@@ -35,8 +35,8 @@ select '(Joe,Blow) /'::fullname;  -- bad
 SELECT pg_input_is_valid('(1,2)', 'complex');
 SELECT pg_input_is_valid('(1,2', 'complex');
 SELECT pg_input_is_valid('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,1e400)', 'complex');
+SELECT pg_input_error_info('(1,zed)', 'complex');
+SELECT pg_input_error_info('(1,1e400)', 'complex');
 
 create temp table quadtable(f1 int, q quad);
 
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 932f71cbca..7d774315c6 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -87,9 +87,9 @@ SELECT E'De\\123dBeEf'::bytea;
 
 -- Test non-error-throwing API too
 SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
+SELECT pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+SELECT pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+SELECT pg_input_error_info(E'foo\\99bar', 'bytea');
 
 --
 -- test conversions between various string types
diff --git a/src/test/regress/sql/tid.sql b/src/test/regress/sql/tid.sql
index 8196194c04..2d2dcb05c1 100644
--- a/src/test/regress/sql/tid.sql
+++ b/src/test/regress/sql/tid.sql
@@ -11,9 +11,9 @@ SELECT '(1,65536)'::tid;  -- error
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('(0)', 'tid');
-SELECT pg_input_error_message('(0)', 'tid');
+SELECT pg_input_error_info('(0)', 'tid');
 SELECT pg_input_is_valid('(0,-1)', 'tid');
-SELECT pg_input_error_message('(0,-1)', 'tid');
+SELECT pg_input_error_info('(0,-1)', 'tid');
 
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/sql/time.sql b/src/test/regress/sql/time.sql
index b439cd6b41..a40e725eab 100644
--- a/src/test/regress/sql/time.sql
+++ b/src/test/regress/sql/time.sql
@@ -44,8 +44,8 @@ SELECT '25:00:00'::time;  -- not allowed
 SELECT pg_input_is_valid('12:00:00', 'time');
 SELECT pg_input_is_valid('25:00:00', 'time');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
-SELECT pg_input_error_message('25:00:00', 'time');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
+SELECT pg_input_error_info('25:00:00', 'time');
+SELECT pg_input_error_info('15:36:39 America/New_York', 'time');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index 2d5f01ab86..ca4c44130a 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -100,8 +100,8 @@ INSERT INTO TIMESTAMP_TBL VALUES ('19970710 173201 America/Does_not_exist');
 SELECT pg_input_is_valid('now', 'timestamp');
 SELECT pg_input_is_valid('garbage', 'timestamp');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-SELECT pg_input_error_message('garbage', 'timestamp');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+SELECT pg_input_error_info('garbage', 'timestamp');
+SELECT pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index 6d10937d86..96cd82fa08 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -113,8 +113,8 @@ SELECT '205000-01-10 17:32:01 Europe/Helsinki'::timestamptz; -- non-DST
 SELECT pg_input_is_valid('now', 'timestamptz');
 SELECT pg_input_is_valid('garbage', 'timestamptz');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-SELECT pg_input_error_message('garbage', 'timestamptz');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+SELECT pg_input_error_info('garbage', 'timestamptz');
+SELECT pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timetz.sql b/src/test/regress/sql/timetz.sql
index b62aa3fe05..857408b88b 100644
--- a/src/test/regress/sql/timetz.sql
+++ b/src/test/regress/sql/timetz.sql
@@ -49,8 +49,8 @@ SELECT '25:00:00 PDT'::timetz;  -- not allowed
 SELECT pg_input_is_valid('12:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('25:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
+SELECT pg_input_error_info('25:00:00 PDT', 'timetz');
+SELECT pg_input_error_info('15:36:39 America/New_York', 'timetz');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql
index b73dd1cb07..9343266fd5 100644
--- a/src/test/regress/sql/tstypes.sql
+++ b/src/test/regress/sql/tstypes.sql
@@ -22,7 +22,7 @@ SELECT $$'' '1' '2'$$::tsvector;  -- error, empty lexeme is not allowed
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsvector');
 SELECT pg_input_is_valid($$''$$, 'tsvector');
-SELECT pg_input_error_message($$''$$, 'tsvector');
+SELECT pg_input_error_info($$''$$, 'tsvector');
 
 --Base tsquery test
 SELECT '1'::tsquery;
@@ -76,8 +76,8 @@ SELECT '!!a & !!b'::tsquery;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsquery');
 SELECT pg_input_is_valid('foo!', 'tsquery');
-SELECT pg_input_error_message('foo!', 'tsquery');
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
+SELECT pg_input_error_info('foo!', 'tsquery');
+SELECT pg_input_error_info('a <100000> b', 'tsquery');
 
 --comparisons
 SELECT 'a' < 'b & c'::tsquery as "true";
diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql
index 37d954eda1..076cf1b21e 100644
--- a/src/test/regress/sql/uuid.sql
+++ b/src/test/regress/sql/uuid.sql
@@ -25,7 +25,7 @@ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('11', 'uuid');
-SELECT pg_input_error_message('11', 'uuid');
+SELECT pg_input_error_info('11', 'uuid');
 
 --inserting three input formats
 INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
diff --git a/src/test/regress/sql/varchar.sql b/src/test/regress/sql/varchar.sql
index df16da37a7..32dbee58b1 100644
--- a/src/test/regress/sql/varchar.sql
+++ b/src/test/regress/sql/varchar.sql
@@ -70,4 +70,4 @@ SELECT * FROM VARCHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'varchar(4)');
 SELECT pg_input_is_valid('abcde', 'varchar(4)');
-SELECT pg_input_error_message('abcde', 'varchar(4)');
+SELECT pg_input_error_info('abcde', 'varchar(4)');
diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql
index b6996588ef..3e5e880473 100644
--- a/src/test/regress/sql/xid.sql
+++ b/src/test/regress/sql/xid.sql
@@ -19,10 +19,10 @@ select 'asdf'::xid8;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('42', 'xid');
 SELECT pg_input_is_valid('asdf', 'xid');
-SELECT pg_input_error_message('0xffffffffff', 'xid');
+SELECT pg_input_error_info('0xffffffffff', 'xid');
 SELECT pg_input_is_valid('42', 'xid8');
 SELECT pg_input_is_valid('asdf', 'xid8');
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
+SELECT pg_input_error_info('0xffffffffffffffffffff', 'xid8');
 
 -- equality
 select '1'::xid = '1'::xid;
@@ -79,9 +79,9 @@ select '12:16:14,13'::pg_snapshot;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('12:13:', 'pg_snapshot');
 select pg_input_is_valid('31:12:', 'pg_snapshot');
-select pg_input_error_message('31:12:', 'pg_snapshot');
+select pg_input_error_info('31:12:', 'pg_snapshot');
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
+select pg_input_error_info('12:16:14,13', 'pg_snapshot');
 
 create temp table snapshot_test (
 	nr	integer,
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ddff459297..24e40d2653 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -12,9 +12,9 @@ SELECT * FROM xmltest;
 -- test non-throwing API, too
 SELECT pg_input_is_valid('<value>one</value>', 'xml');
 SELECT pg_input_is_valid('<value>one</', 'xml');
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 
 
 SELECT xmlcomment('test');
-- 
2.25.1

#13Michael Paquier
michael@paquier.xyz
In reply to: Nathan Bossart (#12)
Re: verbose mode for pg_input_error_message?

On Sat, Feb 25, 2023 at 08:58:17PM -0800, Nathan Bossart wrote:

pg_input_error_info() seems more descriptive to me. I changed the name to
that in v4.

error_info() is fine by me. My recent history is poor lately when it
comes to name new things.

+       values[0] = CStringGetTextDatum(escontext.error_data->message);
+
+       if (escontext.error_data->detail != NULL)
+           values[1] = CStringGetTextDatum(escontext.error_data->detail);
+       else
+           isnull[1] = true;
+
+       if (escontext.error_data->hint != NULL)
+           values[2] = CStringGetTextDatum(escontext.error_data->hint);
+       else
+           isnull[2] = true;
+
+       values[3] = CStringGetTextDatum(
+           unpack_sql_state(escontext.error_data->sqlerrcode));

I am OK with this data set as well. If somebody makes a case about
more fields in ErrorData, we could always consider these separately.

FWIW, I would like to change some of the regression tests as we are
bikeshedding the whole.

+SELECT pg_input_error_info(repeat('too_long', 32), 'rainbow');
For example, we could use the expanded display for this case in
enum.sql.

 -- test non-error-throwing API
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       pg_input_error_info(str,'jsonpath') as errmsg
This case in jsonpath.sql is actually wrong, because we have more than
just the error message.

For the others, I would make the choice of expanding the calls of
pg_input_error_info() rather than just showing row outputs, though I
agree that this part is minor.
--
Michael

#14Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#13)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On Sun, Feb 26, 2023 at 02:35:22PM +0900, Michael Paquier wrote:

For the others, I would make the choice of expanding the calls of
pg_input_error_info() rather than just showing row outputs, though I
agree that this part is minor.

While bike-shedding all the regression tests, I have noticed that
float4-misrounded-input.out was missing a refresh (the query was
right, not the output). The rest was pretty much OK for me, still I
found all the errmsg aliases a bit out of context as the function is
now extended with more attributes, so I have painted a couple of
LATERALs over that.

Are you OK with the attached?
--
Michael

Attachments:

v5-0001-add-details-to-pg_input_error_message-and-rename-.patchtext/x-diff; charset=us-asciiDownload
From b69f4eaff5b4fd5401fc749ba27ead1626852fe8 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 27 Feb 2023 15:36:53 +0900
Subject: [PATCH v5] add details to pg_input_error_message and rename to
 pg_input_error_info

---
 src/include/catalog/pg_proc.dat               |  10 +-
 src/backend/utils/adt/misc.c                  |  42 +++++--
 src/test/regress/expected/arrays.out          |   8 +-
 src/test/regress/expected/bit.out             |  40 +++---
 src/test/regress/expected/boolean.out         |   8 +-
 src/test/regress/expected/box.out             |  16 +--
 src/test/regress/expected/char.out            |   8 +-
 src/test/regress/expected/char_1.out          |   8 +-
 src/test/regress/expected/char_2.out          |   8 +-
 src/test/regress/expected/date.out            |  16 +--
 src/test/regress/expected/domain.out          |  34 +++---
 src/test/regress/expected/enum.out            |  21 ++--
 .../expected/float4-misrounded-input.out      |   8 +-
 src/test/regress/expected/float4.out          |   8 +-
 src/test/regress/expected/float8.out          |   8 +-
 src/test/regress/expected/geometry.out        |  16 +--
 src/test/regress/expected/inet.out            |  24 ++--
 src/test/regress/expected/int2.out            |  24 ++--
 src/test/regress/expected/int4.out            |   8 +-
 src/test/regress/expected/int8.out            |   8 +-
 src/test/regress/expected/interval.out        |  16 +--
 src/test/regress/expected/json.out            |   8 +-
 src/test/regress/expected/json_encoding.out   |   8 +-
 src/test/regress/expected/json_encoding_1.out |   8 +-
 src/test/regress/expected/jsonb.out           |  16 +--
 src/test/regress/expected/jsonpath.out        |  22 ++--
 src/test/regress/expected/line.out            |  40 +++---
 src/test/regress/expected/lseg.out            |   8 +-
 src/test/regress/expected/macaddr.out         |  16 +--
 src/test/regress/expected/macaddr8.out        |  16 +--
 src/test/regress/expected/money.out           |  16 +--
 src/test/regress/expected/multirangetypes.out |  16 +--
 src/test/regress/expected/numeric.out         |  24 ++--
 src/test/regress/expected/oid.out             |  32 ++---
 src/test/regress/expected/path.out            |  16 +--
 src/test/regress/expected/pg_lsn.out          |   8 +-
 src/test/regress/expected/point.out           |   8 +-
 src/test/regress/expected/polygon.out         |  16 +--
 src/test/regress/expected/privileges.out      |  24 ++--
 src/test/regress/expected/rangetypes.out      |  40 +++---
 src/test/regress/expected/regproc.out         | 114 +++++++++---------
 src/test/regress/expected/rowtypes.out        |  16 +--
 src/test/regress/expected/strings.out         |  24 ++--
 src/test/regress/expected/tid.out             |  16 +--
 src/test/regress/expected/time.out            |  16 +--
 src/test/regress/expected/timestamp.out       |  16 +--
 src/test/regress/expected/timestamptz.out     |  16 +--
 src/test/regress/expected/timetz.out          |  16 +--
 src/test/regress/expected/tstypes.out         |  24 ++--
 src/test/regress/expected/uuid.out            |   8 +-
 src/test/regress/expected/varchar.out         |   8 +-
 src/test/regress/expected/varchar_1.out       |   8 +-
 src/test/regress/expected/varchar_2.out       |   8 +-
 src/test/regress/expected/xid.out             |  32 ++---
 src/test/regress/expected/xml.out             |  10 +-
 src/test/regress/expected/xml_1.out           |   4 +-
 src/test/regress/expected/xml_2.out           |   8 +-
 src/test/regress/sql/arrays.sql               |   2 +-
 src/test/regress/sql/bit.sql                  |  10 +-
 src/test/regress/sql/boolean.sql              |   2 +-
 src/test/regress/sql/box.sql                  |   4 +-
 src/test/regress/sql/char.sql                 |   2 +-
 src/test/regress/sql/date.sql                 |   4 +-
 src/test/regress/sql/domain.sql               |  10 +-
 src/test/regress/sql/enum.sql                 |   6 +-
 src/test/regress/sql/float4.sql               |   2 +-
 src/test/regress/sql/float8.sql               |   2 +-
 src/test/regress/sql/geometry.sql             |   4 +-
 src/test/regress/sql/inet.sql                 |   6 +-
 src/test/regress/sql/int2.sql                 |   6 +-
 src/test/regress/sql/int4.sql                 |   2 +-
 src/test/regress/sql/int8.sql                 |   2 +-
 src/test/regress/sql/interval.sql             |   4 +-
 src/test/regress/sql/json.sql                 |   2 +-
 src/test/regress/sql/json_encoding.sql        |   2 +-
 src/test/regress/sql/jsonb.sql                |   4 +-
 src/test/regress/sql/jsonpath.sql             |   8 +-
 src/test/regress/sql/line.sql                 |  10 +-
 src/test/regress/sql/lseg.sql                 |   2 +-
 src/test/regress/sql/macaddr.sql              |   4 +-
 src/test/regress/sql/macaddr8.sql             |   4 +-
 src/test/regress/sql/money.sql                |   4 +-
 src/test/regress/sql/multirangetypes.sql      |   4 +-
 src/test/regress/sql/numeric.sql              |   6 +-
 src/test/regress/sql/oid.sql                  |   8 +-
 src/test/regress/sql/path.sql                 |   4 +-
 src/test/regress/sql/pg_lsn.sql               |   2 +-
 src/test/regress/sql/point.sql                |   2 +-
 src/test/regress/sql/polygon.sql              |   4 +-
 src/test/regress/sql/privileges.sql           |   6 +-
 src/test/regress/sql/rangetypes.sql           |  10 +-
 src/test/regress/sql/regproc.sql              |  34 +++---
 src/test/regress/sql/rowtypes.sql             |   4 +-
 src/test/regress/sql/strings.sql              |   6 +-
 src/test/regress/sql/tid.sql                  |   4 +-
 src/test/regress/sql/time.sql                 |   4 +-
 src/test/regress/sql/timestamp.sql            |   4 +-
 src/test/regress/sql/timestamptz.sql          |   4 +-
 src/test/regress/sql/timetz.sql               |   4 +-
 src/test/regress/sql/tstypes.sql              |   6 +-
 src/test/regress/sql/uuid.sql                 |   2 +-
 src/test/regress/sql/varchar.sql              |   2 +-
 src/test/regress/sql/xid.sql                  |   8 +-
 src/test/regress/sql/xml.sql                  |   4 +-
 doc/src/sgml/func.sgml                        |  33 +++--
 contrib/cube/expected/cube.out                |   8 +-
 contrib/cube/sql/cube.sql                     |   2 +-
 contrib/hstore/expected/hstore.out            |  16 +--
 contrib/hstore/sql/hstore.sql                 |   4 +-
 contrib/intarray/expected/_int.out            |  18 +--
 contrib/intarray/sql/_int.sql                 |   8 +-
 contrib/isn/expected/isn.out                  |  18 +--
 contrib/isn/sql/isn.sql                       |   8 +-
 contrib/ltree/expected/ltree.out              |  28 +++--
 contrib/ltree/sql/ltree.sql                   |   8 +-
 contrib/seg/expected/seg.out                  |  24 ++--
 contrib/seg/sql/seg.sql                       |   8 +-
 117 files changed, 766 insertions(+), 682 deletions(-)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e2a7642a2b..505595620e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7118,9 +7118,13 @@
   proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool',
   proargtypes => 'text text', prosrc => 'pg_input_is_valid' },
 { oid => '8051',
-  descr => 'get error message if string is not valid input for data type',
-  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
-  proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_info', provolatile => 's', prorettype => 'record',
+  proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_info' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index f95256efd3..182d16cdcd 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -660,32 +660,58 @@ pg_input_is_valid(PG_FUNCTION_ARGS)
 }
 
 /*
- * pg_input_error_message - test whether string is valid input for datatype.
+ * pg_input_error_info - test whether string is valid input for datatype.
  *
- * Returns NULL if OK, else the primary message string from the error.
+ * Returns NULL if OK, else the primary message, detail message, hint message,
+ * and sql error code from the error.
  *
  * This will only work usefully if the datatype's input function has been
  * updated to return "soft" errors via errsave/ereturn.
  */
 Datum
-pg_input_error_message(PG_FUNCTION_ARGS)
+pg_input_error_info(PG_FUNCTION_ARGS)
 {
 	text	   *txt = PG_GETARG_TEXT_PP(0);
 	text	   *typname = PG_GETARG_TEXT_PP(1);
 	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
 	/* Enable details_wanted */
 	escontext.details_wanted = true;
 
 	if (pg_input_is_valid_common(fcinfo, txt, typname,
 								 &escontext))
-		PG_RETURN_NULL();
+		memset(isnull, true, sizeof(isnull));
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
 
-	Assert(escontext.error_occurred);
-	Assert(escontext.error_data != NULL);
-	Assert(escontext.error_data->message != NULL);
+		memset(isnull, false, sizeof(isnull));
 
-	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
+
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
+
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /* Common subroutine for the above */
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..0ff54a18de 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -201,10 +201,10 @@ SELECT pg_input_is_valid('{1,zed}', 'integer[]');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+SELECT * FROM pg_input_error_info('{1,zed}', 'integer[]');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 -- test mixed slice/scalar subscripting
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 209044713c..98c2655039 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -753,10 +753,10 @@ SELECT pg_input_is_valid('01010001', 'bit(10)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010001', 'bit(10)');
-             pg_input_error_message              
--------------------------------------------------
- bit string length 8 does not match type bit(10)
+SELECT * FROM pg_input_error_info('01010001', 'bit(10)');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ bit string length 8 does not match type bit(10) |        |      | 22026
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
@@ -765,10 +765,10 @@ SELECT pg_input_is_valid('01010Z01', 'bit(8)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT * FROM pg_input_error_info('01010Z01', 'bit(8)');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ "Z" is not a valid binary digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
@@ -777,10 +777,10 @@ SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT * FROM pg_input_error_info('x01010Z01', 'bit(32)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ "Z" is not a valid hexadecimal digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
@@ -789,10 +789,10 @@ SELECT pg_input_is_valid('01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'varbit');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT * FROM pg_input_error_info('01010Z01', 'varbit');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ "Z" is not a valid binary digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
@@ -801,9 +801,9 @@ SELECT pg_input_is_valid('x01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'varbit');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT * FROM pg_input_error_info('x01010Z01', 'varbit');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ "Z" is not a valid hexadecimal digit |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/boolean.out b/src/test/regress/expected/boolean.out
index 977124b20b..ee9c244bf8 100644
--- a/src/test/regress/expected/boolean.out
+++ b/src/test/regress/expected/boolean.out
@@ -155,10 +155,10 @@ SELECT pg_input_is_valid('asdf', 'bool');
  f
 (1 row)
 
-SELECT pg_input_error_message('junk', 'bool');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type boolean: "junk"
+SELECT * FROM pg_input_error_info('junk', 'bool');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type boolean: "junk" |        |      | 22P02
 (1 row)
 
 -- and, or, not in qualifications
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 0d70194def..8c9e9e3935 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -646,10 +646,10 @@ SELECT pg_input_is_valid('200', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('200', 'box');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type box: "200"
+SELECT * FROM pg_input_error_info('200', 'box');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type box: "200" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
@@ -658,9 +658,9 @@ SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-                   pg_input_error_message                    
--------------------------------------------------------------
- invalid input syntax for type box: "((200,300),(500, xyz))"
+SELECT * FROM pg_input_error_info('((200,300),(500, xyz))', 'box');
+                           message                           | detail | hint | sql_error_code 
+-------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type box: "((200,300),(500, xyz))" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/char.out b/src/test/regress/expected/char.out
index 199001b2fe..b4ecf51dae 100644
--- a/src/test/regress/expected/char.out
+++ b/src/test/regress/expected/char.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_1.out b/src/test/regress/expected/char_1.out
index 3dcb0daa0d..3add81e9f0 100644
--- a/src/test/regress/expected/char_1.out
+++ b/src/test/regress/expected/char_1.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_2.out b/src/test/regress/expected/char_2.out
index dd5d34fe8d..d990f21ece 100644
--- a/src/test/regress/expected/char_2.out
+++ b/src/test/regress/expected/char_2.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index c0dec448e1..f5949f3d17 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -859,16 +859,16 @@ SELECT pg_input_is_valid('6874898-01-01', 'date');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'date');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type date: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'date');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type date: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('6874898-01-01', 'date');
-       pg_input_error_message       
-------------------------------------
- date out of range: "6874898-01-01"
+SELECT * FROM pg_input_error_info('6874898-01-01', 'date');
+              message               | detail | hint | sql_error_code 
+------------------------------------+--------+------+----------------
+ date out of range: "6874898-01-01" |        |      | 22008
 (1 row)
 
 RESET datestyle;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 25f6bb9e1f..b7937fb3bc 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -108,32 +108,32 @@ select pg_input_is_valid('-1', 'positiveint');
  f
 (1 row)
 
-select pg_input_error_message('junk', 'positiveint');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type integer: "junk"
+select * from pg_input_error_info('junk', 'positiveint');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "junk" |        |      | 22P02
 (1 row)
 
-select pg_input_error_message('-1', 'positiveint');
-                           pg_input_error_message                           
-----------------------------------------------------------------------------
- value for domain positiveint violates check constraint "positiveint_check"
+select * from pg_input_error_info('-1', 'positiveint');
+                                  message                                   | detail | hint | sql_error_code 
+----------------------------------------------------------------------------+--------+------+----------------
+ value for domain positiveint violates check constraint "positiveint_check" |        |      | 23514
 (1 row)
 
-select pg_input_error_message('junk', 'weirdfloat');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type double precision: "junk"
+select * from pg_input_error_info('junk', 'weirdfloat');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type double precision: "junk" |        |      | 22P02
 (1 row)
 
-select pg_input_error_message('0.01', 'weirdfloat');
-                          pg_input_error_message                          
---------------------------------------------------------------------------
- value for domain weirdfloat violates check constraint "weirdfloat_check"
+select * from pg_input_error_info('0.01', 'weirdfloat');
+                                 message                                  | detail | hint | sql_error_code 
+--------------------------------------------------------------------------+--------+------+----------------
+ value for domain weirdfloat violates check constraint "weirdfloat_check" |        |      | 23514
 (1 row)
 
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select * from pg_input_error_info('0', 'weirdfloat');
 ERROR:  division by zero
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4b45fcf8f0..01159688e5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -37,18 +37,21 @@ SELECT pg_input_is_valid('mauve', 'rainbow');
  f
 (1 row)
 
-SELECT pg_input_error_message('mauve', 'rainbow');
-            pg_input_error_message             
------------------------------------------------
- invalid input value for enum rainbow: "mauve"
+SELECT * FROM pg_input_error_info('mauve', 'rainbow');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input value for enum rainbow: "mauve" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
-                                                                                                                                          pg_input_error_message                                                                                                                                          
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
-(1 row)
+\x
+SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
+-[ RECORD 1 ]--+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+message        | invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
+detail         | 
+hint           | 
+sql_error_code | 22P02
 
+\x
 --
 -- adding new values
 --
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
index 24fde6cc9f..a427231627 100644
--- a/src/test/regress/expected/float4-misrounded-input.out
+++ b/src/test/regress/expected/float4-misrounded-input.out
@@ -100,10 +100,10 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+SELECT * FROM pg_input_error_info('1e400', 'float4');
+                message                | detail | hint | sql_error_code 
+---------------------------------------+--------+------+----------------
+ "1e400" is out of range for type real |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 1d7090a90d..65ee82caae 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -100,10 +100,10 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+SELECT * FROM pg_input_error_info('1e400', 'float4');
+                message                | detail | hint | sql_error_code 
+---------------------------------------+--------+------+----------------
+ "1e400" is out of range for type real |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 2b25784f7f..c98407ef0a 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('1e4000', 'float8');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e4000', 'float8');
-               pg_input_error_message               
-----------------------------------------------------
- "1e4000" is out of range for type double precision
+SELECT * FROM pg_input_error_info('1e4000', 'float8');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ "1e4000" is out of range for type double precision |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 291cacdf4f..8be694f46b 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5302,10 +5302,10 @@ SELECT pg_input_is_valid('(1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,', 'circle');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type circle: "1,"
+SELECT * FROM pg_input_error_info('1,', 'circle');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type circle: "1," |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
@@ -5314,9 +5314,9 @@ SELECT pg_input_is_valid('(1,2),-1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,2),-1', 'circle');
-              pg_input_error_message              
---------------------------------------------------
- invalid input syntax for type circle: "(1,2),-1"
+SELECT * FROM pg_input_error_info('(1,2),-1', 'circle');
+                     message                      | detail | hint | sql_error_code 
+--------------------------------------------------+--------+------+----------------
+ invalid input syntax for type circle: "(1,2),-1" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index c9f466ac1d..b6895d9ced 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1063,10 +1063,10 @@ SELECT pg_input_is_valid('1234', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'cidr');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type cidr: "1234"
+SELECT * FROM pg_input_error_info('1234', 'cidr');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type cidr: "1234" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
@@ -1075,10 +1075,10 @@ SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
-          pg_input_error_message          
-------------------------------------------
- invalid cidr value: "192.168.198.200/24"
+SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr');
+                 message                  |                detail                | hint | sql_error_code 
+------------------------------------------+--------------------------------------+------+----------------
+ invalid cidr value: "192.168.198.200/24" | Value has bits set to right of mask. |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('1234', 'inet');
@@ -1087,9 +1087,9 @@ SELECT pg_input_is_valid('1234', 'inet');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'inet');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type inet: "1234"
+SELECT * FROM pg_input_error_info('1234', 'inet');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type inet: "1234" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 73b4ee023c..4e03a5faee 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('50000', 'int2');
  f
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT * FROM pg_input_error_info('50000', 'int2');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "50000" is out of range for type smallint |        |      | 22003
 (1 row)
 
 -- While we're here, check int2vector as well
@@ -77,16 +77,16 @@ SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
  t
 (1 row)
 
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-             pg_input_error_message             
-------------------------------------------------
- invalid input syntax for type smallint: "asdf"
+SELECT * FROM pg_input_error_info('1 asdf', 'int2vector');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ invalid input syntax for type smallint: "asdf" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2vector');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT * FROM pg_input_error_info('50000', 'int2vector');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "50000" is out of range for type smallint |        |      | 22003
 (1 row)
 
 SELECT * FROM INT2_TBL AS f(a, b);
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 9c20574ca5..b1a15888ef 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('1000000000000', 'int4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1000000000000', 'int4');
-                 pg_input_error_message                 
---------------------------------------------------------
- value "1000000000000" is out of range for type integer
+SELECT * FROM pg_input_error_info('1000000000000', 'int4');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ value "1000000000000" is out of range for type integer |        |      | 22003
 (1 row)
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index d9dca64e88..9542d622ba 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('10000000000000000000', 'int8');
  f
 (1 row)
 
-SELECT pg_input_error_message('10000000000000000000', 'int8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "10000000000000000000" is out of range for type bigint
+SELECT * FROM pg_input_error_info('10000000000000000000', 'int8');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "10000000000000000000" is out of range for type bigint |        |      | 22003
 (1 row)
 
 -- int8/int8 cmp
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a154840c85..28b71d9681 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -91,16 +91,16 @@ SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'interval');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type interval: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'interval');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type interval: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type interval: "@ 30 eons ago"
+SELECT * FROM pg_input_error_info('@ 30 eons ago', 'interval');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type interval: "@ 30 eons ago" |        |      | 22007
 (1 row)
 
 -- test interval operators
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index af96ce4180..56dba9d6e2 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -333,10 +333,10 @@ select pg_input_is_valid('{"a":true', 'json');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'json');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select * from pg_input_error_info('{"a":true', 'json');
+              message               |                detail                | hint | sql_error_code 
+------------------------------------+--------------------------------------+------+----------------
+ invalid input syntax for type json | The input string ended unexpectedly. |      | 22P02
 (1 row)
 
 --constructors
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
index 083621fb21..f18ba9ebb2 100644
--- a/src/test/regress/expected/json_encoding.out
+++ b/src/test/regress/expected/json_encoding.out
@@ -261,9 +261,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
- pg_input_error_message 
-------------------------
- 
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+ message | detail | hint | sql_error_code 
+---------+--------+------+----------------
+         |        |      | 
 (1 row)
 
diff --git a/src/test/regress/expected/json_encoding_1.out b/src/test/regress/expected/json_encoding_1.out
index 021d226f8d..eb1ae227b0 100644
--- a/src/test/regress/expected/json_encoding_1.out
+++ b/src/test/regress/expected/json_encoding_1.out
@@ -257,9 +257,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
-       pg_input_error_message        
--------------------------------------
- unsupported Unicode escape sequence
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+               message               |                                      detail                                      | hint | sql_error_code 
+-------------------------------------+----------------------------------------------------------------------------------+------+----------------
+ unsupported Unicode escape sequence | Unicode escape value could not be translated to the server's encoding SQL_ASCII. | null | 22P05
 (1 row)
 
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index d3248aa0fd..4a16d0dbaf 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -323,16 +323,16 @@ select pg_input_is_valid('{"a":true', 'jsonb');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'jsonb');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select * from pg_input_error_info('{"a":true', 'jsonb');
+              message               |                detail                | hint | sql_error_code 
+------------------------------------+--------------------------------------+------+----------------
+ invalid input syntax for type json | The input string ended unexpectedly. |      | 22P02
 (1 row)
 
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+select * from pg_input_error_info('{"a":1e1000000}', 'jsonb');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ value overflows numeric format |        |      | 22003
 (1 row)
 
 -- make sure jsonb is passed through json generators without being escaped
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index ca0cdf1ab2..f866fb474f 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -1035,18 +1035,22 @@ select '1?(2>3)'::jsonpath;
 -- test non-error-throwing API
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
                   '00',
-                  '1a']) str;
-                 jsonpath                  | ok |                                errmsg                                 
--------------------------------------------+----+-----------------------------------------------------------------------
- $ ? (@ like_regex "pattern" flag "smixq") | t  | 
- $ ? (@ like_regex "pattern" flag "a")     | f  | invalid input syntax for type jsonpath
- @ + 1                                     | f  | @ is not allowed in root expressions
- 00                                        | f  | trailing junk after numeric literal at or near "00" of jsonpath input
- 1a                                        | f  | trailing junk after numeric literal at or near "1a" of jsonpath input
+                  '1a']) str,
+     LATERAL pg_input_error_info(str, 'jsonpath') as errinfo;
+                 jsonpath                  | ok | sql_error_code |                                message                                |                          detail                          | hint 
+-------------------------------------------+----+----------------+-----------------------------------------------------------------------+----------------------------------------------------------+------
+ $ ? (@ like_regex "pattern" flag "smixq") | t  |                |                                                                       |                                                          | 
+ $ ? (@ like_regex "pattern" flag "a")     | f  | 42601          | invalid input syntax for type jsonpath                                | Unrecognized flag character "a" in LIKE_REGEX predicate. | 
+ @ + 1                                     | f  | 42601          | @ is not allowed in root expressions                                  |                                                          | 
+ 00                                        | f  | 42601          | trailing junk after numeric literal at or near "00" of jsonpath input |                                                          | 
+ 1a                                        | f  | 42601          | trailing junk after numeric literal at or near "1a" of jsonpath input |                                                          | 
 (5 rows)
 
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index 6baea8fdbd..e7d4332877 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -92,10 +92,10 @@ SELECT pg_input_is_valid('{1, 1}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1}', 'line');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type line: "{1, 1}"
+SELECT * FROM pg_input_error_info('{1, 1}', 'line');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type line: "{1, 1}" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
@@ -104,10 +104,10 @@ SELECT pg_input_is_valid('{0, 0, 0}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid line specification: A and B cannot both be zero
+SELECT * FROM pg_input_error_info('{0, 0, 0}', 'line');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid line specification: A and B cannot both be zero |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
@@ -116,10 +116,10 @@ SELECT pg_input_is_valid('{1, 1, a}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, a}', 'line');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type line: "{1, 1, a}"
+SELECT * FROM pg_input_error_info('{1, 1, a}', 'line');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ invalid input syntax for type line: "{1, 1, a}" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
@@ -128,10 +128,10 @@ SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('{1, 1, 1e400}', 'line');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
@@ -140,9 +140,9 @@ SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('(1, 1), (1, 1e400)', 'line');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index afb323fe04..c0375ac3f3 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -49,9 +49,9 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type lseg: "[(1,2),(3)]"
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'lseg');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type lseg: "[(1,2),(3)]" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index cb646af79b..8d5b22195a 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -165,10 +165,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
-                   pg_input_error_message                   
-------------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
+                          message                           | detail | hint | sql_error_code 
+------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
@@ -177,9 +177,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index bf681988f8..460e8506b6 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -359,10 +359,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
@@ -371,9 +371,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
+                             message                             | detail | hint | sql_error_code 
+-----------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 46b2eab51a..7fd4e31804 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -338,10 +338,10 @@ SELECT pg_input_is_valid('\x0001', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('\x0001', 'money');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type money: "\x0001"
+SELECT * FROM pg_input_error_info('\x0001', 'money');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type money: "\x0001" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
@@ -350,10 +350,10 @@ SELECT pg_input_is_valid('192233720368547758.07', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('192233720368547758.07', 'money');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "192233720368547758.07" is out of range for type money
+SELECT * FROM pg_input_error_info('192233720368547758.07', 'money');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "192233720368547758.07" is out of range for type money |        |      | 22003
 (1 row)
 
 -- documented minimums and maximums
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index e70896b754..a0cb875492 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -287,10 +287,10 @@ select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
-            pg_input_error_message             
------------------------------------------------
- malformed multirange literal: "{[1,2], [4,5]"
+select * from pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
+                    message                    |          detail          | hint | sql_error_code 
+-----------------------------------------------+--------------------------+------+----------------
+ malformed multirange literal: "{[1,2], [4,5]" | Unexpected end of input. |      | 22P02
 (1 row)
 
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
@@ -299,10 +299,10 @@ select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select * from pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 56a3f3630a..2ac2c99b19 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2312,10 +2312,10 @@ SELECT pg_input_is_valid('1e400000', 'numeric');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400000', 'numeric');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+SELECT * FROM pg_input_error_info('1e400000', 'numeric');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ value overflows numeric format |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
@@ -2330,16 +2330,16 @@ SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
- pg_input_error_message 
-------------------------
- numeric field overflow
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code 
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
 (1 row)
 
-SELECT pg_input_error_message('0x1234.567', 'numeric');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type numeric: "0x1234.567"
+SELECT * FROM pg_input_error_info('0x1234.567', 'numeric');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type numeric: "0x1234.567" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/oid.out b/src/test/regress/expected/oid.out
index b664bab5f9..b80cb47e0c 100644
--- a/src/test/regress/expected/oid.out
+++ b/src/test/regress/expected/oid.out
@@ -78,10 +78,10 @@ SELECT pg_input_is_valid('01XYZ', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('01XYZ', 'oid');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type oid: "01XYZ"
+SELECT * FROM pg_input_error_info('01XYZ', 'oid');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type oid: "01XYZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('9999999999', 'oid');
@@ -90,10 +90,10 @@ SELECT pg_input_is_valid('9999999999', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('9999999999', 'oid');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT * FROM pg_input_error_info('9999999999', 'oid');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "9999999999" is out of range for type oid |        |      | 22003
 (1 row)
 
 -- While we're here, check oidvector as well
@@ -109,10 +109,10 @@ SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type oid: "XYZ"
+SELECT * FROM pg_input_error_info('01 01XYZ', 'oidvector');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type oid: "XYZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
@@ -121,10 +121,10 @@ SELECT pg_input_is_valid('01 9999999999', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT * FROM pg_input_error_info('01 9999999999', 'oidvector');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "9999999999" is out of range for type oid |        |      | 22003
 (1 row)
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 529a5e6fc2..4994641bde 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type path: "[(1,2),(3)]"
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'path');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type path: "[(1,2),(3)]" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
@@ -99,9 +99,9 @@ SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type path: "[(1,2,6),(3,4,6)]"
+SELECT * FROM pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type path: "[(1,2,6),(3,4,6)]" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out
index 01501f8c9b..b27eec7c01 100644
--- a/src/test/regress/expected/pg_lsn.out
+++ b/src/test/regress/expected/pg_lsn.out
@@ -33,10 +33,10 @@ SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
  f
 (1 row)
 
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type pg_lsn: "16AE7F7"
+SELECT * FROM pg_input_error_info('16AE7F7', 'pg_lsn');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_lsn: "16AE7F7" |        |      | 22P02
 (1 row)
 
 -- Min/Max aggregation
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index a716ceb881..ba508c3ea4 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -470,9 +470,9 @@ SELECT pg_input_is_valid('1,y', 'point');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,y', 'point');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type point: "1,y"
+SELECT * FROM pg_input_error_info('1,y', 'point');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type point: "1,y" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index c7d565ad53..7a9778e70f 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -313,10 +313,10 @@ SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type polygon: "(2.0,0.8,0.1)"
+SELECT * FROM pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type polygon: "(2.0,0.8,0.1)" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
@@ -325,9 +325,9 @@ SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type polygon: "(2.0,xyz)"
+SELECT * FROM pg_input_error_info('(2.0,xyz)', 'polygon');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type polygon: "(2.0,xyz)" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 95d1e5515f..5496ec8f55 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2246,10 +2246,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
-     pg_input_error_message      
----------------------------------
- a name must follow the "/" sign
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/', 'aclitem');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ a name must follow the "/" sign |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
@@ -2258,10 +2258,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem')
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-           pg_input_error_message           
---------------------------------------------
- role "regress_no_such_user" does not exist
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ role "regress_no_such_user" does not exist |        |      | 42704
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
@@ -2270,10 +2270,10 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm"
+SELECT * FROM pg_input_error_info('regress_priv_user1=rY', 'aclitem');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid mode character: must be one of "arwdDxtXUCTcsAm" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a3e9e447af..ee02ff0163 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -188,10 +188,10 @@ select pg_input_is_valid('(1,4', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(1,4', 'int4range');
-     pg_input_error_message      
----------------------------------
- malformed range literal: "(1,4"
+select * from pg_input_error_info('(1,4', 'int4range');
+             message             |          detail          | hint | sql_error_code 
+---------------------------------+--------------------------+------+----------------
+ malformed range literal: "(1,4" | Unexpected end of input. |      | 22P02
 (1 row)
 
 select pg_input_is_valid('(4,1)', 'int4range');
@@ -200,10 +200,10 @@ select pg_input_is_valid('(4,1)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,1)', 'int4range');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- range lower bound must be less than or equal to range upper bound
+select * from pg_input_error_info('(4,1)', 'int4range');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ range lower bound must be less than or equal to range upper bound |        |      | 22000
 (1 row)
 
 select pg_input_is_valid('(4,zed)', 'int4range');
@@ -212,10 +212,10 @@ select pg_input_is_valid('(4,zed)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,zed)', 'int4range');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select * from pg_input_error_info('(4,zed)', 'int4range');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 select pg_input_is_valid('[1,2147483647]', 'int4range');
@@ -224,10 +224,10 @@ select pg_input_is_valid('[1,2147483647]', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('[1,2147483647]', 'int4range');
- pg_input_error_message 
-------------------------
- integer out of range
+select * from pg_input_error_info('[1,2147483647]', 'int4range');
+       message        | detail | hint | sql_error_code 
+----------------------+--------+------+----------------
+ integer out of range |        |      | 22003
 (1 row)
 
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
@@ -236,10 +236,10 @@ select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
  f
 (1 row)
 
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
- pg_input_error_message 
-------------------------
- date out of range
+select * from pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
+      message      | detail | hint | sql_error_code 
+-------------------+--------+------+----------------
+ date out of range |        |      | 22008
 (1 row)
 
 --
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..a9420850b8 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -448,10 +448,10 @@ SELECT to_regnamespace('foo.bar');
 (1 row)
 
 -- Test soft-error API
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
-            pg_input_error_message             
------------------------------------------------
- relation "ng_catalog.pg_class" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ relation "ng_catalog.pg_class" does not exist |        |      | 42P01
 (1 row)
 
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
@@ -460,87 +460,87 @@ SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
  f
 (1 row)
 
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-                  pg_input_error_message                   
------------------------------------------------------------
- text search configuration "no_such_config" does not exist
+SELECT * FROM pg_input_error_info('no_such_config', 'regconfig');
+                          message                          | detail | hint | sql_error_code 
+-----------------------------------------------------------+--------+------+----------------
+ text search configuration "no_such_config" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-                   pg_input_error_message                   
-------------------------------------------------------------
- text search dictionary "no_such_dictionary" does not exist
+SELECT * FROM pg_input_error_info('no_such_dictionary', 'regdictionary');
+                          message                           | detail | hint | sql_error_code 
+------------------------------------------------------------+--------+------+----------------
+ text search dictionary "no_such_dictionary" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-       pg_input_error_message        
--------------------------------------
- schema "nonexistent" does not exist
+SELECT * FROM pg_input_error_info('Nonexistent', 'regnamespace');
+               message               | detail | hint | sql_error_code 
+-------------------------------------+--------+------+----------------
+ schema "nonexistent" does not exist |        |      | 3F000
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-         pg_input_error_message          
------------------------------------------
- operator does not exist: ng_catalog.||/
+SELECT * FROM pg_input_error_info('ng_catalog.||/', 'regoper');
+                 message                 | detail | hint | sql_error_code 
+-----------------------------------------+--------+------+----------------
+ operator does not exist: ng_catalog.||/ |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoper');
-     pg_input_error_message     
---------------------------------
- more than one operator named -
+SELECT * FROM pg_input_error_info('-', 'regoper');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ more than one operator named - |        |      | 42725
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-              pg_input_error_message              
---------------------------------------------------
- operator does not exist: ng_catalog.+(int4,int4)
+SELECT * FROM pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+                     message                      | detail | hint | sql_error_code 
+--------------------------------------------------+--------+------+----------------
+ operator does not exist: ng_catalog.+(int4,int4) |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoperator');
-   pg_input_error_message    
------------------------------
- expected a left parenthesis
+SELECT * FROM pg_input_error_info('-', 'regoperator');
+           message           | detail | hint | sql_error_code 
+-----------------------------+--------+------+----------------
+ expected a left parenthesis |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-          pg_input_error_message          
-------------------------------------------
- function "ng_catalog.now" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.now', 'regproc');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ function "ng_catalog.now" does not exist |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-              pg_input_error_message               
----------------------------------------------------
- function "ng_catalog.abs(numeric)" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ function "ng_catalog.abs(numeric)" does not exist |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-    pg_input_error_message    
-------------------------------
- expected a right parenthesis
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+           message            | detail | hint | sql_error_code 
+------------------------------+--------+------+----------------
+ expected a right parenthesis |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-           pg_input_error_message           
---------------------------------------------
- role "regress_regrole_test" does not exist
+SELECT * FROM pg_input_error_info('regress_regrole_test', 'regrole');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ role "regress_regrole_test" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('no_such_type', 'regtype');
-       pg_input_error_message       
-------------------------------------
- type "no_such_type" does not exist
+SELECT * FROM pg_input_error_info('no_such_type', 'regtype');
+              message               | detail | hint | sql_error_code 
+------------------------------------+--------+------+----------------
+ type "no_such_type" does not exist |        |      | 42704
 (1 row)
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
+SELECT * FROM pg_input_error_info('incorrect type name syntax', 'regtype');
 ERROR:  syntax error at or near "type"
-LINE 1: SELECT pg_input_error_message('incorrect type name syntax', ...
+LINE 1: SELECT * FROM pg_input_error_info('incorrect type name synta...
                   ^
 CONTEXT:  invalid type name "incorrect type name syntax"
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT * FROM pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
 ERROR:  invalid NUMERIC type modifier
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
+SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
 ERROR:  improper qualified name (too many dotted names): way.too.many.names
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
 ERROR:  cross-database references are not implemented: no_such_catalog.schema.name
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 801d9e556b..2ee6b1829b 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -88,16 +88,16 @@ SELECT pg_input_is_valid('(1,zed)', 'complex');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,zed)', 'complex');
-                pg_input_error_message                 
--------------------------------------------------------
- invalid input syntax for type double precision: "zed"
+SELECT * FROM pg_input_error_info('(1,zed)', 'complex');
+                        message                        | detail | hint | sql_error_code 
+-------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type double precision: "zed" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('(1,1e400)', 'complex');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('(1,1e400)', 'complex');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
 create temp table quadtable(f1 int, q quad);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index f028c1f10f..403a29ed8c 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -280,22 +280,22 @@ SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
  f
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-             pg_input_error_message             
-------------------------------------------------
- invalid hexadecimal data: odd number of digits
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ invalid hexadecimal data: odd number of digits |        |      | 22023
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-     pg_input_error_message     
---------------------------------
- invalid hexadecimal digit: "x"
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ invalid hexadecimal digit: "x" |        |      | 22023
 (1 row)
 
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
-       pg_input_error_message        
--------------------------------------
- invalid input syntax for type bytea
+SELECT * FROM pg_input_error_info(E'foo\\99bar', 'bytea');
+               message               | detail | hint | sql_error_code 
+-------------------------------------+--------+------+----------------
+ invalid input syntax for type bytea |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out
index ff67ed43f0..083c83a1e1 100644
--- a/src/test/regress/expected/tid.out
+++ b/src/test/regress/expected/tid.out
@@ -24,10 +24,10 @@ SELECT pg_input_is_valid('(0)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0)', 'tid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type tid: "(0)"
+SELECT * FROM pg_input_error_info('(0)', 'tid');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type tid: "(0)" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(0,-1)', 'tid');
@@ -36,10 +36,10 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0,-1)', 'tid');
-           pg_input_error_message            
----------------------------------------------
- invalid input syntax for type tid: "(0,-1)"
+SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
+                   message                   | detail | hint | sql_error_code 
+---------------------------------------------+--------+------+----------------
+ invalid input syntax for type tid: "(0,-1)" |        |      | 22P02
 (1 row)
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index a44caededd..4247fae941 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -133,16 +133,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00', 'time');
-             pg_input_error_message             
-------------------------------------------------
- date/time field value out of range: "25:00:00"
+SELECT * FROM pg_input_error_info('25:00:00', 'time');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ date/time field value out of range: "25:00:00" |        |      | 22008
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type time: "15:36:39 America/New_York"
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'time');
+                             message                             | detail | hint | sql_error_code 
+-----------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type time: "15:36:39 America/New_York" |        |      | 22007
 (1 row)
 
 --
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index eef2f7001c..c64bcb7c12 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -144,16 +144,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamp');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type timestamp: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'timestamp');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type timestamp: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ time zone "nehwon/lankhmar" not recognized |        |      | 22023
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index b85a93a3c2..91d7c1f5cc 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -195,16 +195,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamptz');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type timestamp with time zone: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'timestamptz');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type timestamp with time zone: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ time zone "nehwon/lankhmar" not recognized |        |      | 22023
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 984285663b..be49588b6d 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -150,16 +150,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-               pg_input_error_message               
-----------------------------------------------------
- date/time field value out of range: "25:00:00 PDT"
+SELECT * FROM pg_input_error_info('25:00:00 PDT', 'timetz');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ date/time field value out of range: "25:00:00 PDT" |        |      | 22008
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
-                             pg_input_error_message                             
---------------------------------------------------------------------------------
- invalid input syntax for type time with time zone: "15:36:39 America/New_York"
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'timetz');
+                                    message                                     | detail | hint | sql_error_code 
+--------------------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type time with time zone: "15:36:39 America/New_York" |        |      | 22007
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index a8785cd708..4cfc3b9dc0 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -102,10 +102,10 @@ SELECT pg_input_is_valid($$''$$, 'tsvector');
  f
 (1 row)
 
-SELECT pg_input_error_message($$''$$, 'tsvector');
-     pg_input_error_message     
---------------------------------
- syntax error in tsvector: "''"
+SELECT * FROM pg_input_error_info($$''$$, 'tsvector');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ syntax error in tsvector: "''" |        |      | 42601
 (1 row)
 
 --Base tsquery test
@@ -404,16 +404,16 @@ SELECT pg_input_is_valid('foo!', 'tsquery');
  f
 (1 row)
 
-SELECT pg_input_error_message('foo!', 'tsquery');
-     pg_input_error_message      
----------------------------------
- syntax error in tsquery: "foo!"
+SELECT * FROM pg_input_error_info('foo!', 'tsquery');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ syntax error in tsquery: "foo!" |        |      | 42601
 (1 row)
 
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
-                                pg_input_error_message                                 
----------------------------------------------------------------------------------------
- distance in phrase operator must be an integer value between zero and 16384 inclusive
+SELECT * FROM pg_input_error_info('a <100000> b', 'tsquery');
+                                        message                                        | detail | hint | sql_error_code 
+---------------------------------------------------------------------------------------+--------+------+----------------
+ distance in phrase operator must be an integer value between zero and 16384 inclusive |        |      | 22023
 (1 row)
 
 --comparisons
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 0f47232009..8e7f21910d 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -46,10 +46,10 @@ SELECT pg_input_is_valid('11', 'uuid');
  f
 (1 row)
 
-SELECT pg_input_error_message('11', 'uuid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type uuid: "11"
+SELECT * FROM pg_input_error_info('11', 'uuid');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type uuid: "11" |        |      | 22P02
 (1 row)
 
 --inserting three input formats
diff --git a/src/test/regress/expected/varchar.out b/src/test/regress/expected/varchar.out
index 62b683d86f..ae8c043d33 100644
--- a/src/test/regress/expected/varchar.out
+++ b/src/test/regress/expected/varchar.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_1.out b/src/test/regress/expected/varchar_1.out
index 6690f81c0b..7cb74c752a 100644
--- a/src/test/regress/expected/varchar_1.out
+++ b/src/test/regress/expected/varchar_1.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_2.out b/src/test/regress/expected/varchar_2.out
index ad8aa7c693..9b154c6ca5 100644
--- a/src/test/regress/expected/varchar_2.out
+++ b/src/test/regress/expected/varchar_2.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index e62f701943..835077e9d5 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -43,10 +43,10 @@ SELECT pg_input_is_valid('asdf', 'xid');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffff', 'xid');
-              pg_input_error_message               
----------------------------------------------------
- value "0xffffffffff" is out of range for type xid
+SELECT * FROM pg_input_error_info('0xffffffffff', 'xid');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ value "0xffffffffff" is out of range for type xid |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('42', 'xid8');
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('asdf', 'xid8');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "0xffffffffffffffffffff" is out of range for type xid8
+SELECT * FROM pg_input_error_info('0xffffffffffffffffffff', 'xid8');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "0xffffffffffffffffffff" is out of range for type xid8 |        |      | 22003
 (1 row)
 
 -- equality
@@ -223,10 +223,10 @@ select pg_input_is_valid('31:12:', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('31:12:', 'pg_snapshot');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type pg_snapshot: "31:12:"
+select * from pg_input_error_info('31:12:', 'pg_snapshot');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_snapshot: "31:12:" |        |      | 22P02
 (1 row)
 
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
@@ -235,10 +235,10 @@ select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type pg_snapshot: "12:16:14,13"
+select * from pg_input_error_info('12:16:14,13', 'pg_snapshot');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_snapshot: "12:16:14,13" |        |      | 22P02
 (1 row)
 
 create temp table snapshot_test (
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..ad852dc2f7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -31,9 +31,9 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
-------------------------
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message       
+---------------------
  invalid XML content
 (1 row)
 
@@ -43,8 +43,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 378b412db0..70fe34a04f 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -29,13 +29,13 @@ DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlcomment('test');
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 42055c5003..e01f431219 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -29,8 +29,8 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message          
 ------------------------
  invalid XML content
 (1 row)
@@ -41,8 +41,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 38e8dd440b..6ea4dba9f1 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -117,7 +117,7 @@ SELECT a,b,c FROM arrtest;
 SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
 SELECT pg_input_is_valid('{1,2', 'integer[]');
 SELECT pg_input_is_valid('{1,zed}', 'integer[]');
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
+SELECT * FROM pg_input_error_info('{1,zed}', 'integer[]');
 
 -- test mixed slice/scalar subscripting
 select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 8814249c2a..2cd550d27e 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -232,13 +232,13 @@ TABLE bit_defaults;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('01010001', 'bit(10)');
-SELECT pg_input_error_message('01010001', 'bit(10)');
+SELECT * FROM pg_input_error_info('01010001', 'bit(10)');
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
+SELECT * FROM pg_input_error_info('01010Z01', 'bit(8)');
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
+SELECT * FROM pg_input_error_info('x01010Z01', 'bit(32)');
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
-SELECT pg_input_error_message('01010Z01', 'varbit');
+SELECT * FROM pg_input_error_info('01010Z01', 'varbit');
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
-SELECT pg_input_error_message('x01010Z01', 'varbit');
+SELECT * FROM pg_input_error_info('x01010Z01', 'varbit');
diff --git a/src/test/regress/sql/boolean.sql b/src/test/regress/sql/boolean.sql
index dfaa55dd0f..bc9937d692 100644
--- a/src/test/regress/sql/boolean.sql
+++ b/src/test/regress/sql/boolean.sql
@@ -65,7 +65,7 @@ SELECT bool '' AS error;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('true', 'bool');
 SELECT pg_input_is_valid('asdf', 'bool');
-SELECT pg_input_error_message('junk', 'bool');
+SELECT * FROM pg_input_error_info('junk', 'bool');
 
 -- and, or, not in qualifications
 
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 02e100391b..2d0868e889 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -284,6 +284,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('200', 'box');
-SELECT pg_input_error_message('200', 'box');
+SELECT * FROM pg_input_error_info('200', 'box');
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
+SELECT * FROM pg_input_error_info('((200,300),(500, xyz))', 'box');
diff --git a/src/test/regress/sql/char.sql b/src/test/regress/sql/char.sql
index 8aa43b0fb8..fdda9d1929 100644
--- a/src/test/regress/sql/char.sql
+++ b/src/test/regress/sql/char.sql
@@ -75,7 +75,7 @@ SELECT * FROM CHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'char(4)');
 SELECT pg_input_is_valid('abcde', 'char(4)');
-SELECT pg_input_error_message('abcde', 'char(4)');
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
 
 --
 -- Also test "char", which is an ad-hoc one-byte type.  It can only
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql
index 89982dd2f8..1c58ff6966 100644
--- a/src/test/regress/sql/date.sql
+++ b/src/test/regress/sql/date.sql
@@ -197,8 +197,8 @@ SELECT date '5874898-01-01';  -- out of range
 SELECT pg_input_is_valid('now', 'date');
 SELECT pg_input_is_valid('garbage', 'date');
 SELECT pg_input_is_valid('6874898-01-01', 'date');
-SELECT pg_input_error_message('garbage', 'date');
-SELECT pg_input_error_message('6874898-01-01', 'date');
+SELECT * FROM pg_input_error_info('garbage', 'date');
+SELECT * FROM pg_input_error_info('6874898-01-01', 'date');
 
 RESET datestyle;
 
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 1558bd9a33..a9a56f5277 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -77,12 +77,12 @@ create domain weirdfloat float8 check((1 / value) < 10);
 select pg_input_is_valid('1', 'positiveint');
 select pg_input_is_valid('junk', 'positiveint');
 select pg_input_is_valid('-1', 'positiveint');
-select pg_input_error_message('junk', 'positiveint');
-select pg_input_error_message('-1', 'positiveint');
-select pg_input_error_message('junk', 'weirdfloat');
-select pg_input_error_message('0.01', 'weirdfloat');
+select * from pg_input_error_info('junk', 'positiveint');
+select * from pg_input_error_info('-1', 'positiveint');
+select * from pg_input_error_info('junk', 'weirdfloat');
+select * from pg_input_error_info('0.01', 'weirdfloat');
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select * from pg_input_error_info('0', 'weirdfloat');
 
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index c87656589b..93171379f2 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -18,8 +18,10 @@ SELECT 'mauve'::rainbow;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('red', 'rainbow');
 SELECT pg_input_is_valid('mauve', 'rainbow');
-SELECT pg_input_error_message('mauve', 'rainbow');
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
+SELECT * FROM pg_input_error_info('mauve', 'rainbow');
+\x
+SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
+\x
 
 --
 -- adding new values
diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4.sql
index 061477726b..8fb12368c3 100644
--- a/src/test/regress/sql/float4.sql
+++ b/src/test/regress/sql/float4.sql
@@ -40,7 +40,7 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
 SELECT pg_input_is_valid('34.5', 'float4');
 SELECT pg_input_is_valid('xyz', 'float4');
 SELECT pg_input_is_valid('1e400', 'float4');
-SELECT pg_input_error_message('1e400', 'float4');
+SELECT * FROM pg_input_error_info('1e400', 'float4');
 
 -- special inputs
 SELECT 'NaN'::float4;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index c276a5324c..8acef0fbab 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -38,7 +38,7 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123           5');
 SELECT pg_input_is_valid('34.5', 'float8');
 SELECT pg_input_is_valid('xyz', 'float8');
 SELECT pg_input_is_valid('1e4000', 'float8');
-SELECT pg_input_error_message('1e4000', 'float8');
+SELECT * FROM pg_input_error_info('1e4000', 'float8');
 
 -- special inputs
 SELECT 'NaN'::float8;
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 309234b76c..c3ea368da5 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -526,6 +526,6 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(1', 'circle');
-SELECT pg_input_error_message('1,', 'circle');
+SELECT * FROM pg_input_error_info('1,', 'circle');
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
-SELECT pg_input_error_message('(1,2),-1', 'circle');
+SELECT * FROM pg_input_error_info('(1,2),-1', 'circle');
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index abfcd4242f..3910eac3bc 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -255,9 +255,9 @@ SELECT a FROM (VALUES
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1234', 'cidr');
-SELECT pg_input_error_message('1234', 'cidr');
+SELECT * FROM pg_input_error_info('1234', 'cidr');
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
+SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr');
 
 SELECT pg_input_is_valid('1234', 'inet');
-SELECT pg_input_error_message('1234', 'inet');
+SELECT * FROM pg_input_error_info('1234', 'inet');
diff --git a/src/test/regress/sql/int2.sql b/src/test/regress/sql/int2.sql
index ce8ac97963..df1e46d4e2 100644
--- a/src/test/regress/sql/int2.sql
+++ b/src/test/regress/sql/int2.sql
@@ -21,12 +21,12 @@ SELECT * FROM INT2_TBL;
 SELECT pg_input_is_valid('34', 'int2');
 SELECT pg_input_is_valid('asdf', 'int2');
 SELECT pg_input_is_valid('50000', 'int2');
-SELECT pg_input_error_message('50000', 'int2');
+SELECT * FROM pg_input_error_info('50000', 'int2');
 
 -- While we're here, check int2vector as well
 SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-SELECT pg_input_error_message('50000', 'int2vector');
+SELECT * FROM pg_input_error_info('1 asdf', 'int2vector');
+SELECT * FROM pg_input_error_info('50000', 'int2vector');
 
 SELECT * FROM INT2_TBL AS f(a, b);
 
diff --git a/src/test/regress/sql/int4.sql b/src/test/regress/sql/int4.sql
index 146963edfb..e9d89e8111 100644
--- a/src/test/regress/sql/int4.sql
+++ b/src/test/regress/sql/int4.sql
@@ -21,7 +21,7 @@ SELECT * FROM INT4_TBL;
 SELECT pg_input_is_valid('34', 'int4');
 SELECT pg_input_is_valid('asdf', 'int4');
 SELECT pg_input_is_valid('1000000000000', 'int4');
-SELECT pg_input_error_message('1000000000000', 'int4');
+SELECT * FROM pg_input_error_info('1000000000000', 'int4');
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
 
diff --git a/src/test/regress/sql/int8.sql b/src/test/regress/sql/int8.sql
index c85717c072..33f664dd02 100644
--- a/src/test/regress/sql/int8.sql
+++ b/src/test/regress/sql/int8.sql
@@ -20,7 +20,7 @@ SELECT * FROM INT8_TBL;
 SELECT pg_input_is_valid('34', 'int8');
 SELECT pg_input_is_valid('asdf', 'int8');
 SELECT pg_input_is_valid('10000000000000000000', 'int8');
-SELECT pg_input_error_message('10000000000000000000', 'int8');
+SELECT * FROM pg_input_error_info('10000000000000000000', 'int8');
 
 -- int8/int8 cmp
 SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index af8e1ca0f4..56feda1a3d 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -36,8 +36,8 @@ INSERT INTO INTERVAL_TBL (f1) VALUES ('@ 30 eons ago');
 SELECT pg_input_is_valid('1.5 weeks', 'interval');
 SELECT pg_input_is_valid('garbage', 'interval');
 SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
-SELECT pg_input_error_message('garbage', 'interval');
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
+SELECT * FROM pg_input_error_info('garbage', 'interval');
+SELECT * FROM pg_input_error_info('@ 30 eons ago', 'interval');
 
 -- test interval operators
 
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 21534ed959..ec57dfe707 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -84,7 +84,7 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'json');
 select pg_input_is_valid('{"a":true', 'json');
-select pg_input_error_message('{"a":true', 'json');
+select * from pg_input_error_info('{"a":true', 'json');
 
 --constructors
 -- array_to_json
diff --git a/src/test/regress/sql/json_encoding.sql b/src/test/regress/sql/json_encoding.sql
index f87b3bd4f3..aceb8dbc3c 100644
--- a/src/test/regress/sql/json_encoding.sql
+++ b/src/test/regress/sql/json_encoding.sql
@@ -79,4 +79,4 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 
 -- soft error for input-time failure
 
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 9f67f4c71d..e4b7cdf703 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -89,8 +89,8 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'jsonb');
 select pg_input_is_valid('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
+select * from pg_input_error_info('{"a":true', 'jsonb');
+select * from pg_input_error_info('{"a":1e1000000}', 'jsonb');
 
 -- make sure jsonb is passed through json generators without being escaped
 SELECT array_to_json(ARRAY [jsonb '{"a":1}', jsonb '{"b":[2,3]}']);
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 99d21d2af7..f2cd632729 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -192,9 +192,13 @@ select '1?(2>3)'::jsonpath;
 
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
                   '00',
-                  '1a']) str;
+                  '1a']) str,
+     LATERAL pg_input_error_info(str, 'jsonpath') as errinfo;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index f706a41184..1d0d3689c3 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -43,12 +43,12 @@ select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('{1, 1}', 'line');
-SELECT pg_input_error_message('{1, 1}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1}', 'line');
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
+SELECT * FROM pg_input_error_info('{0, 0, 0}', 'line');
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
-SELECT pg_input_error_message('{1, 1, a}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1, a}', 'line');
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1, 1e400}', 'line');
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
+SELECT * FROM pg_input_error_info('(1, 1), (1, 1e400)', 'line');
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 0fece162e0..d38a83eea6 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -25,4 +25,4 @@ select * from LSEG_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'lseg');
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index 211397c8f3..f61bdebe86 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -44,6 +44,6 @@ DROP TABLE macaddr_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
index b29f785b41..3c0cd70285 100644
--- a/src/test/regress/sql/macaddr8.sql
+++ b/src/test/regress/sql/macaddr8.sql
@@ -90,6 +90,6 @@ DROP TABLE macaddr8_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql
index cd9a089e01..81c92dd960 100644
--- a/src/test/regress/sql/money.sql
+++ b/src/test/regress/sql/money.sql
@@ -90,9 +90,9 @@ SELECT '($123,456.78)'::money;
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('\x0001', 'money');
-SELECT pg_input_error_message('\x0001', 'money');
+SELECT * FROM pg_input_error_info('\x0001', 'money');
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
-SELECT pg_input_error_message('192233720368547758.07', 'money');
+SELECT * FROM pg_input_error_info('192233720368547758.07', 'money');
 
 -- documented minimums and maximums
 SELECT '-92233720368547758.08'::money;
diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql
index fc369a550c..fefb4b4d42 100644
--- a/src/test/regress/sql/multirangetypes.sql
+++ b/src/test/regress/sql/multirangetypes.sql
@@ -61,9 +61,9 @@ select '{(a,a)}'::textmultirange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('{[1,2], [4,5]}', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
+select * from pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
+select * from pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
 
 --
 -- test the constructor
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 2db7656e84..6e9e6145d0 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1086,11 +1086,11 @@ SELECT * FROM num_input_test;
 SELECT pg_input_is_valid('34.5', 'numeric');
 SELECT pg_input_is_valid('34xyz', 'numeric');
 SELECT pg_input_is_valid('1e400000', 'numeric');
-SELECT pg_input_error_message('1e400000', 'numeric');
+SELECT * FROM pg_input_error_info('1e400000', 'numeric');
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
 SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('0x1234.567', 'numeric');
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+SELECT * FROM pg_input_error_info('0x1234.567', 'numeric');
 
 --
 -- Test precision and scale typemods
diff --git a/src/test/regress/sql/oid.sql b/src/test/regress/sql/oid.sql
index 39937c2f1d..a96b2aa1e3 100644
--- a/src/test/regress/sql/oid.sql
+++ b/src/test/regress/sql/oid.sql
@@ -31,16 +31,16 @@ SELECT * FROM OID_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('1234', 'oid');
 SELECT pg_input_is_valid('01XYZ', 'oid');
-SELECT pg_input_error_message('01XYZ', 'oid');
+SELECT * FROM pg_input_error_info('01XYZ', 'oid');
 SELECT pg_input_is_valid('9999999999', 'oid');
-SELECT pg_input_error_message('9999999999', 'oid');
+SELECT * FROM pg_input_error_info('9999999999', 'oid');
 
 -- While we're here, check oidvector as well
 SELECT pg_input_is_valid(' 1 2  4 ', 'oidvector');
 SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
+SELECT * FROM pg_input_error_info('01 01XYZ', 'oidvector');
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
+SELECT * FROM pg_input_error_info('01 9999999999', 'oidvector');
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
 
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 42c90afe53..8422ba961c 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -45,6 +45,6 @@ SELECT popen(f1) AS open_path FROM PATH_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'path');
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
+SELECT * FROM pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
diff --git a/src/test/regress/sql/pg_lsn.sql b/src/test/regress/sql/pg_lsn.sql
index 3d57d66e0c..98c869df15 100644
--- a/src/test/regress/sql/pg_lsn.sql
+++ b/src/test/regress/sql/pg_lsn.sql
@@ -17,7 +17,7 @@ INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
+SELECT * FROM pg_input_error_info('16AE7F7', 'pg_lsn');
 
 -- Min/Max aggregation
 SELECT MIN(f1), MAX(f1) FROM PG_LSN_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 7bd1ebe2b5..b1a29eb229 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -99,4 +99,4 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1,y', 'point');
-SELECT pg_input_error_message('1,y', 'point');
+SELECT * FROM pg_input_error_info('1,y', 'point');
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index da644e34e3..9f6c5d5ea1 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -143,6 +143,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
+SELECT * FROM pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
+SELECT * FROM pg_input_error_info('(2.0,xyz)', 'polygon');
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 0bcea77ff4..134809e8cc 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -1433,11 +1433,11 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
 -- Test non-throwing aclitem I/O
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=rY', 'aclitem');
 
 --
 -- Testing blanket default grants is very hazardous since it might change
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index 4e6a0912de..c23be928c3 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -43,15 +43,15 @@ select '(a,a)'::textrange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('(1,4)', 'int4range');
 select pg_input_is_valid('(1,4', 'int4range');
-select pg_input_error_message('(1,4', 'int4range');
+select * from pg_input_error_info('(1,4', 'int4range');
 select pg_input_is_valid('(4,1)', 'int4range');
-select pg_input_error_message('(4,1)', 'int4range');
+select * from pg_input_error_info('(4,1)', 'int4range');
 select pg_input_is_valid('(4,zed)', 'int4range');
-select pg_input_error_message('(4,zed)', 'int4range');
+select * from pg_input_error_info('(4,zed)', 'int4range');
 select pg_input_is_valid('[1,2147483647]', 'int4range');
-select pg_input_error_message('[1,2147483647]', 'int4range');
+select * from pg_input_error_info('[1,2147483647]', 'int4range');
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
+select * from pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
 
 --
 -- create some test data and test the operators
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index 2cb8c9a253..de2aa881a8 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -125,23 +125,23 @@ SELECT to_regnamespace('foo.bar');
 
 -- Test soft-error API
 
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
+SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-SELECT pg_input_error_message('-', 'regoper');
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-SELECT pg_input_error_message('-', 'regoperator');
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-SELECT pg_input_error_message('no_such_type', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_config', 'regconfig');
+SELECT * FROM pg_input_error_info('no_such_dictionary', 'regdictionary');
+SELECT * FROM pg_input_error_info('Nonexistent', 'regnamespace');
+SELECT * FROM pg_input_error_info('ng_catalog.||/', 'regoper');
+SELECT * FROM pg_input_error_info('-', 'regoper');
+SELECT * FROM pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+SELECT * FROM pg_input_error_info('-', 'regoperator');
+SELECT * FROM pg_input_error_info('ng_catalog.now', 'regproc');
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+SELECT * FROM pg_input_error_info('regress_regrole_test', 'regrole');
+SELECT * FROM pg_input_error_info('no_such_type', 'regtype');
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT * FROM pg_input_error_info('incorrect type name syntax', 'regtype');
+SELECT * FROM pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql
index 0844e7488d..1ec2824516 100644
--- a/src/test/regress/sql/rowtypes.sql
+++ b/src/test/regress/sql/rowtypes.sql
@@ -35,8 +35,8 @@ select '(Joe,Blow) /'::fullname;  -- bad
 SELECT pg_input_is_valid('(1,2)', 'complex');
 SELECT pg_input_is_valid('(1,2', 'complex');
 SELECT pg_input_is_valid('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,1e400)', 'complex');
+SELECT * FROM pg_input_error_info('(1,zed)', 'complex');
+SELECT * FROM pg_input_error_info('(1,1e400)', 'complex');
 
 create temp table quadtable(f1 int, q quad);
 
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 932f71cbca..097dcdf69e 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -87,9 +87,9 @@ SELECT E'De\\123dBeEf'::bytea;
 
 -- Test non-error-throwing API too
 SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+SELECT * FROM pg_input_error_info(E'foo\\99bar', 'bytea');
 
 --
 -- test conversions between various string types
diff --git a/src/test/regress/sql/tid.sql b/src/test/regress/sql/tid.sql
index 8196194c04..2602e20eb5 100644
--- a/src/test/regress/sql/tid.sql
+++ b/src/test/regress/sql/tid.sql
@@ -11,9 +11,9 @@ SELECT '(1,65536)'::tid;  -- error
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('(0)', 'tid');
-SELECT pg_input_error_message('(0)', 'tid');
+SELECT * FROM pg_input_error_info('(0)', 'tid');
 SELECT pg_input_is_valid('(0,-1)', 'tid');
-SELECT pg_input_error_message('(0,-1)', 'tid');
+SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
 
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/sql/time.sql b/src/test/regress/sql/time.sql
index b439cd6b41..eb375a36e9 100644
--- a/src/test/regress/sql/time.sql
+++ b/src/test/regress/sql/time.sql
@@ -44,8 +44,8 @@ SELECT '25:00:00'::time;  -- not allowed
 SELECT pg_input_is_valid('12:00:00', 'time');
 SELECT pg_input_is_valid('25:00:00', 'time');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
-SELECT pg_input_error_message('25:00:00', 'time');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
+SELECT * FROM pg_input_error_info('25:00:00', 'time');
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'time');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index 2d5f01ab86..b9bcce9cfe 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -100,8 +100,8 @@ INSERT INTO TIMESTAMP_TBL VALUES ('19970710 173201 America/Does_not_exist');
 SELECT pg_input_is_valid('now', 'timestamp');
 SELECT pg_input_is_valid('garbage', 'timestamp');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-SELECT pg_input_error_message('garbage', 'timestamp');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+SELECT * FROM pg_input_error_info('garbage', 'timestamp');
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index 6d10937d86..ae9ee4b56a 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -113,8 +113,8 @@ SELECT '205000-01-10 17:32:01 Europe/Helsinki'::timestamptz; -- non-DST
 SELECT pg_input_is_valid('now', 'timestamptz');
 SELECT pg_input_is_valid('garbage', 'timestamptz');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-SELECT pg_input_error_message('garbage', 'timestamptz');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+SELECT * FROM pg_input_error_info('garbage', 'timestamptz');
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timetz.sql b/src/test/regress/sql/timetz.sql
index b62aa3fe05..93c7bb1428 100644
--- a/src/test/regress/sql/timetz.sql
+++ b/src/test/regress/sql/timetz.sql
@@ -49,8 +49,8 @@ SELECT '25:00:00 PDT'::timetz;  -- not allowed
 SELECT pg_input_is_valid('12:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('25:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
+SELECT * FROM pg_input_error_info('25:00:00 PDT', 'timetz');
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'timetz');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql
index b73dd1cb07..dfb7a1466e 100644
--- a/src/test/regress/sql/tstypes.sql
+++ b/src/test/regress/sql/tstypes.sql
@@ -22,7 +22,7 @@ SELECT $$'' '1' '2'$$::tsvector;  -- error, empty lexeme is not allowed
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsvector');
 SELECT pg_input_is_valid($$''$$, 'tsvector');
-SELECT pg_input_error_message($$''$$, 'tsvector');
+SELECT * FROM pg_input_error_info($$''$$, 'tsvector');
 
 --Base tsquery test
 SELECT '1'::tsquery;
@@ -76,8 +76,8 @@ SELECT '!!a & !!b'::tsquery;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsquery');
 SELECT pg_input_is_valid('foo!', 'tsquery');
-SELECT pg_input_error_message('foo!', 'tsquery');
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
+SELECT * FROM pg_input_error_info('foo!', 'tsquery');
+SELECT * FROM pg_input_error_info('a <100000> b', 'tsquery');
 
 --comparisons
 SELECT 'a' < 'b & c'::tsquery as "true";
diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql
index 37d954eda1..9a8f437c7d 100644
--- a/src/test/regress/sql/uuid.sql
+++ b/src/test/regress/sql/uuid.sql
@@ -25,7 +25,7 @@ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('11', 'uuid');
-SELECT pg_input_error_message('11', 'uuid');
+SELECT * FROM pg_input_error_info('11', 'uuid');
 
 --inserting three input formats
 INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
diff --git a/src/test/regress/sql/varchar.sql b/src/test/regress/sql/varchar.sql
index df16da37a7..c8aaf93e8a 100644
--- a/src/test/regress/sql/varchar.sql
+++ b/src/test/regress/sql/varchar.sql
@@ -70,4 +70,4 @@ SELECT * FROM VARCHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'varchar(4)');
 SELECT pg_input_is_valid('abcde', 'varchar(4)');
-SELECT pg_input_error_message('abcde', 'varchar(4)');
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql
index b6996588ef..9f716b3653 100644
--- a/src/test/regress/sql/xid.sql
+++ b/src/test/regress/sql/xid.sql
@@ -19,10 +19,10 @@ select 'asdf'::xid8;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('42', 'xid');
 SELECT pg_input_is_valid('asdf', 'xid');
-SELECT pg_input_error_message('0xffffffffff', 'xid');
+SELECT * FROM pg_input_error_info('0xffffffffff', 'xid');
 SELECT pg_input_is_valid('42', 'xid8');
 SELECT pg_input_is_valid('asdf', 'xid8');
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
+SELECT * FROM pg_input_error_info('0xffffffffffffffffffff', 'xid8');
 
 -- equality
 select '1'::xid = '1'::xid;
@@ -79,9 +79,9 @@ select '12:16:14,13'::pg_snapshot;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('12:13:', 'pg_snapshot');
 select pg_input_is_valid('31:12:', 'pg_snapshot');
-select pg_input_error_message('31:12:', 'pg_snapshot');
+select * from pg_input_error_info('31:12:', 'pg_snapshot');
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
+select * from pg_input_error_info('12:16:14,13', 'pg_snapshot');
 
 create temp table snapshot_test (
 	nr	integer,
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ddff459297..24e40d2653 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -12,9 +12,9 @@ SELECT * FROM xmltest;
 -- test non-throwing API, too
 SELECT pg_input_is_valid('<value>one</value>', 'xml');
 SELECT pg_input_is_valid('<value>one</', 'xml');
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 
 
 SELECT xmlcomment('test');
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0cbdf63632..97b3f1c1a6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24775,19 +24775,23 @@ SELECT collation for ('foo' COLLATE "de_DE");
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
-         <primary>pg_input_error_message</primary>
+         <primary>pg_input_error_info</primary>
         </indexterm>
-        <function>pg_input_error_message</function> (
+        <function>pg_input_error_info</function> (
           <parameter>string</parameter> <type>text</type>,
           <parameter>type</parameter> <type>text</type>
         )
-        <returnvalue>text</returnvalue>
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
        </para>
        <para>
         Tests whether the given <parameter>string</parameter> is valid
-        input for the specified data type; if not, return the error
-        message that would have been thrown.  If the input is valid, the
-        result is NULL.  The inputs are the same as
+        input for the specified data type; if not, return the details of
+        the error would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
         for <function>pg_input_is_valid</function>.
        </para>
        <para>
@@ -24798,12 +24802,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
         directly.
         </para>
         <para>
-         <literal>pg_input_error_message('42000000000', 'integer')</literal>
-         <returnvalue>value "42000000000" is out of range for type integer</returnvalue>
-        </para>
-        <para>
-         <literal>pg_input_error_message('1234.567', 'numeric(7,4)')</literal>
-         <returnvalue>numeric field overflow</returnvalue>
+<programlisting>
+SELECT * FROM pg_input_error_info('42000000000', 'integer');
+                       message                        | detail | hint | sql_error_code
+------------------------------------------------------+--------+------+----------------
+ value "42000000000" is out of range for type integer |        |      | 22003
+
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
+</programlisting>
        </para></entry>
       </row>
      </tbody>
diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index dc23e5ccc0..47787c50bd 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -344,10 +344,10 @@ SELECT pg_input_is_valid('-1e-700', 'cube');
  f
 (1 row)
 
-SELECT pg_input_error_message('-1e-700', 'cube');
-               pg_input_error_message                
------------------------------------------------------
- "-1e-700" is out of range for type double precision
+SELECT * FROM pg_input_error_info('-1e-700', 'cube');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ "-1e-700" is out of range for type double precision |        |      | 22003
 (1 row)
 
 --
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 384883d16e..eec90d21ee 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -83,7 +83,7 @@ SELECT '-1e-700'::cube AS cube; -- out of range
 SELECT pg_input_is_valid('(1,2)', 'cube');
 SELECT pg_input_is_valid('[(1),]', 'cube');
 SELECT pg_input_is_valid('-1e-700', 'cube');
-SELECT pg_input_error_message('-1e-700', 'cube');
+SELECT * FROM pg_input_error_info('-1e-700', 'cube');
 
 --
 -- Testing building cubes from float8 values
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index d6faa91867..1836c9acf3 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -265,16 +265,16 @@ select pg_input_is_valid('a=b', 'hstore');
  f
 (1 row)
 
-select pg_input_error_message('a=b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "b" at position 2
+select * from pg_input_error_info('a=b', 'hstore');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ syntax error in hstore, near "b" at position 2 |        |      | 42601
 (1 row)
 
-select pg_input_error_message(' =>b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "=" at position 1
+select * from pg_input_error_info(' =>b', 'hstore');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ syntax error in hstore, near "=" at position 1 |        |      | 42601
 (1 row)
 
 -- -> operator
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index 15f4f71416..efef91292a 100644
--- a/contrib/hstore/sql/hstore.sql
+++ b/contrib/hstore/sql/hstore.sql
@@ -60,8 +60,8 @@ select 'aa=>"'::hstore;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('a=>b', 'hstore');
 select pg_input_is_valid('a=b', 'hstore');
-select pg_input_error_message('a=b', 'hstore');
-select pg_input_error_message(' =>b', 'hstore');
+select * from pg_input_error_info('a=b', 'hstore');
+select * from pg_input_error_info(' =>b', 'hstore');
 
 
 -- -> operator
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index c953065a5c..6abb17e2e5 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -401,16 +401,20 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 -- test non-error-throwing input
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
-      AS a(str);
-    query_int    | ok |    errmsg    
------------------+----+--------------
- 1&(2&(4&(5|6))) | t  | 
- 1#(2&(4&(5&6))) | f  | syntax error
- foo             | f  | syntax error
+      AS a(str),
+     LATERAL pg_input_error_info(a.str, 'query_int') as errinfo;
+    query_int    | ok | sql_error_code |   message    | detail | hint 
+-----------------+----+----------------+--------------+--------+------
+ 1&(2&(4&(5|6))) | t  |                |              |        | 
+ 1#(2&(4&(5&6))) | f  | 42601          | syntax error |        | 
+ foo             | f  | 42601          | syntax error |        | 
 (3 rows)
 
 CREATE TABLE test__int( a int[] );
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
index 4c9ba4c1fb..d9d987bdb1 100644
--- a/contrib/intarray/sql/_int.sql
+++ b/contrib/intarray/sql/_int.sql
@@ -79,11 +79,15 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
-      AS a(str);
+      AS a(str),
+     LATERAL pg_input_error_info(a.str, 'query_int') as errinfo;
 
 
 
diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out
index 72171b2790..2f05b7eb86 100644
--- a/contrib/isn/expected/isn.out
+++ b/contrib/isn/expected/isn.out
@@ -263,16 +263,20 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
-      AS a(str,typ);
-      isn      | type  | ok |                         errmsg                         
----------------+-------+----+--------------------------------------------------------
- 9780123456786 | UPC   | f  | cannot cast ISBN to UPC for number: "9780123456786"
- postgresql... | EAN13 | f  | invalid input syntax for EAN13 number: "postgresql..."
- 9771234567003 | ISSN  | t  | 
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
+      isn      | type  | ok | sql_error_code |                        message                         | detail | hint 
+---------------+-------+----+----------------+--------------------------------------------------------+--------+------
+ 9780123456786 | UPC   | f  | 22P02          | cannot cast ISBN to UPC for number: "9780123456786"    |        | 
+ postgresql... | EAN13 | f  | 22P02          | invalid input syntax for EAN13 number: "postgresql..." |        | 
+ 9771234567003 | ISSN  | t  |                |                                                        |        | 
 (3 rows)
 
 --
diff --git a/contrib/isn/sql/isn.sql b/contrib/isn/sql/isn.sql
index 6426cb42a0..2c2ea077d1 100644
--- a/contrib/isn/sql/isn.sql
+++ b/contrib/isn/sql/isn.sql
@@ -110,11 +110,15 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
-      AS a(str,typ);
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
 
 --
 -- cleanup
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index d2a53b9f0c..27122153c7 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -8101,7 +8101,10 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 -- test non-error-throwing input
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
@@ -8110,16 +8113,17 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.3','lquery'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
-      AS a(str,typ);
-     value      |   type    | ok |               errmsg               
-----------------+-----------+----+------------------------------------
- .2.3           | ltree     | f  | ltree syntax error at character 1
- 1.2.           | ltree     | f  | ltree syntax error
- 1.2.3          | ltree     | t  | 
- @.2.3          | lquery    | f  | lquery syntax error at character 1
-  2.3           | lquery    | f  | lquery syntax error at character 1
- 1.2.3          | lquery    | t  | 
- $tree & aWdf@* | ltxtquery | f  | operand syntax error
- !tree & aWdf@* | ltxtquery | t  | 
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
+     value      |   type    | ok | sql_error_code |              message               |          detail          | hint 
+----------------+-----------+----+----------------+------------------------------------+--------------------------+------
+ .2.3           | ltree     | f  | 42601          | ltree syntax error at character 1  |                          | 
+ 1.2.           | ltree     | f  | 42601          | ltree syntax error                 | Unexpected end of input. | 
+ 1.2.3          | ltree     | t  |                |                                    |                          | 
+ @.2.3          | lquery    | f  | 42601          | lquery syntax error at character 1 |                          | 
+  2.3           | lquery    | f  | 42601          | lquery syntax error at character 1 |                          | 
+ 1.2.3          | lquery    | t  |                |                                    |                          | 
+ $tree & aWdf@* | ltxtquery | f  | 42601          | operand syntax error               |                          | 
+ !tree & aWdf@* | ltxtquery | t  |                |                                    |                          | 
 (8 rows)
 
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index 4a6e6266c3..4623b57f7b 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -393,7 +393,10 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
@@ -402,4 +405,5 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.3','lquery'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
-      AS a(str,typ);
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 7a06113ed8..cd21139b5a 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1276,20 +1276,24 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 -- test non error throwing API
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
                   'ABC',
                   '1 e7',
-                  '1e700']) str;
-   seg    | ok |                errmsg                 
-----------+----+---------------------------------------
- -1 .. 1  | t  | 
- 100(+-)1 | t  | 
-          | f  | bad seg representation
- ABC      | f  | bad seg representation
- 1 e7     | f  | bad seg representation
- 1e700    | f  | "1e700" is out of range for type real
+                  '1e700']) str,
+     LATERAL pg_input_error_info(str, 'seg') as errinfo;
+   seg    | ok | sql_error_code |                message                |            detail            | hint 
+----------+----+----------------+---------------------------------------+------------------------------+------
+ -1 .. 1  | t  |                |                                       |                              | 
+ 100(+-)1 | t  |                |                                       |                              | 
+          | f  | 42601          | bad seg representation                | syntax error at end of input | 
+ ABC      | f  | 42601          | bad seg representation                | syntax error at or near "A"  | 
+ 1 e7     | f  | 42601          | bad seg representation                | syntax error at or near "e"  | 
+ 1e700    | f  | 22003          | "1e700" is out of range for type real |                              | 
 (6 rows)
 
diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql
index b9a5d05d09..c30f1f6bef 100644
--- a/contrib/seg/sql/seg.sql
+++ b/contrib/seg/sql/seg.sql
@@ -244,10 +244,14 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
                   'ABC',
                   '1 e7',
-                  '1e700']) str;
+                  '1e700']) str,
+     LATERAL pg_input_error_info(str, 'seg') as errinfo;
-- 
2.39.2

#15Nathan Bossart
nathandbossart@gmail.com
In reply to: Michael Paquier (#14)
1 attachment(s)
Re: verbose mode for pg_input_error_message?

On Mon, Feb 27, 2023 at 03:37:37PM +0900, Michael Paquier wrote:

Are you OK with the attached?

I found a couple of more small changes required to make cfbot happy.
Otherwise, it looks good to me.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

Attachments:

v6-0001-add-details-to-pg_input_error_message-and-rename-.patchtext/x-diff; charset=us-asciiDownload
From 767a9d21a2e25fca2a847a4a9c6036a97c9d8eb9 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 27 Feb 2023 15:36:53 +0900
Subject: [PATCH v6 1/1] add details to pg_input_error_message and rename to
 pg_input_error_info

---
 contrib/cube/expected/cube.out                |   8 +-
 contrib/cube/sql/cube.sql                     |   2 +-
 contrib/hstore/expected/hstore.out            |  16 +--
 contrib/hstore/sql/hstore.sql                 |   4 +-
 contrib/intarray/expected/_int.out            |  18 +--
 contrib/intarray/sql/_int.sql                 |   8 +-
 contrib/isn/expected/isn.out                  |  18 +--
 contrib/isn/sql/isn.sql                       |   8 +-
 contrib/ltree/expected/ltree.out              |  28 +++--
 contrib/ltree/sql/ltree.sql                   |   8 +-
 contrib/seg/expected/seg.out                  |  24 ++--
 contrib/seg/sql/seg.sql                       |   8 +-
 doc/src/sgml/func.sgml                        |  33 +++--
 src/backend/utils/adt/misc.c                  |  42 +++++--
 src/include/catalog/pg_proc.dat               |  10 +-
 src/test/regress/expected/arrays.out          |   8 +-
 src/test/regress/expected/bit.out             |  40 +++---
 src/test/regress/expected/boolean.out         |   8 +-
 src/test/regress/expected/box.out             |  16 +--
 src/test/regress/expected/char.out            |   8 +-
 src/test/regress/expected/char_1.out          |   8 +-
 src/test/regress/expected/char_2.out          |   8 +-
 src/test/regress/expected/date.out            |  16 +--
 src/test/regress/expected/domain.out          |  34 +++---
 src/test/regress/expected/enum.out            |  21 ++--
 .../expected/float4-misrounded-input.out      |   8 +-
 src/test/regress/expected/float4.out          |   8 +-
 src/test/regress/expected/float8.out          |   8 +-
 src/test/regress/expected/geometry.out        |  16 +--
 src/test/regress/expected/inet.out            |  24 ++--
 src/test/regress/expected/int2.out            |  24 ++--
 src/test/regress/expected/int4.out            |   8 +-
 src/test/regress/expected/int8.out            |   8 +-
 src/test/regress/expected/interval.out        |  16 +--
 src/test/regress/expected/json.out            |   8 +-
 src/test/regress/expected/json_encoding.out   |   8 +-
 src/test/regress/expected/json_encoding_1.out |   8 +-
 src/test/regress/expected/jsonb.out           |  16 +--
 src/test/regress/expected/jsonpath.out        |  22 ++--
 src/test/regress/expected/line.out            |  40 +++---
 src/test/regress/expected/lseg.out            |   8 +-
 src/test/regress/expected/macaddr.out         |  16 +--
 src/test/regress/expected/macaddr8.out        |  16 +--
 src/test/regress/expected/money.out           |  16 +--
 src/test/regress/expected/multirangetypes.out |  16 +--
 src/test/regress/expected/numeric.out         |  24 ++--
 src/test/regress/expected/oid.out             |  32 ++---
 src/test/regress/expected/path.out            |  16 +--
 src/test/regress/expected/pg_lsn.out          |   8 +-
 src/test/regress/expected/point.out           |   8 +-
 src/test/regress/expected/polygon.out         |  16 +--
 src/test/regress/expected/privileges.out      |  24 ++--
 src/test/regress/expected/rangetypes.out      |  40 +++---
 src/test/regress/expected/regproc.out         | 114 +++++++++---------
 src/test/regress/expected/rowtypes.out        |  16 +--
 src/test/regress/expected/strings.out         |  24 ++--
 src/test/regress/expected/tid.out             |  16 +--
 src/test/regress/expected/time.out            |  16 +--
 src/test/regress/expected/timestamp.out       |  16 +--
 src/test/regress/expected/timestamptz.out     |  16 +--
 src/test/regress/expected/timetz.out          |  16 +--
 src/test/regress/expected/tstypes.out         |  24 ++--
 src/test/regress/expected/uuid.out            |   8 +-
 src/test/regress/expected/varchar.out         |   8 +-
 src/test/regress/expected/varchar_1.out       |   8 +-
 src/test/regress/expected/varchar_2.out       |   8 +-
 src/test/regress/expected/xid.out             |  32 ++---
 src/test/regress/expected/xml.out             |  10 +-
 src/test/regress/expected/xml_1.out           |   4 +-
 src/test/regress/expected/xml_2.out           |   8 +-
 src/test/regress/sql/arrays.sql               |   2 +-
 src/test/regress/sql/bit.sql                  |  10 +-
 src/test/regress/sql/boolean.sql              |   2 +-
 src/test/regress/sql/box.sql                  |   4 +-
 src/test/regress/sql/char.sql                 |   2 +-
 src/test/regress/sql/date.sql                 |   4 +-
 src/test/regress/sql/domain.sql               |  10 +-
 src/test/regress/sql/enum.sql                 |   6 +-
 src/test/regress/sql/float4.sql               |   2 +-
 src/test/regress/sql/float8.sql               |   2 +-
 src/test/regress/sql/geometry.sql             |   4 +-
 src/test/regress/sql/inet.sql                 |   6 +-
 src/test/regress/sql/int2.sql                 |   6 +-
 src/test/regress/sql/int4.sql                 |   2 +-
 src/test/regress/sql/int8.sql                 |   2 +-
 src/test/regress/sql/interval.sql             |   4 +-
 src/test/regress/sql/json.sql                 |   2 +-
 src/test/regress/sql/json_encoding.sql        |   2 +-
 src/test/regress/sql/jsonb.sql                |   4 +-
 src/test/regress/sql/jsonpath.sql             |   8 +-
 src/test/regress/sql/line.sql                 |  10 +-
 src/test/regress/sql/lseg.sql                 |   2 +-
 src/test/regress/sql/macaddr.sql              |   4 +-
 src/test/regress/sql/macaddr8.sql             |   4 +-
 src/test/regress/sql/money.sql                |   4 +-
 src/test/regress/sql/multirangetypes.sql      |   4 +-
 src/test/regress/sql/numeric.sql              |   6 +-
 src/test/regress/sql/oid.sql                  |   8 +-
 src/test/regress/sql/path.sql                 |   4 +-
 src/test/regress/sql/pg_lsn.sql               |   2 +-
 src/test/regress/sql/point.sql                |   2 +-
 src/test/regress/sql/polygon.sql              |   4 +-
 src/test/regress/sql/privileges.sql           |   6 +-
 src/test/regress/sql/rangetypes.sql           |  10 +-
 src/test/regress/sql/regproc.sql              |  34 +++---
 src/test/regress/sql/rowtypes.sql             |   4 +-
 src/test/regress/sql/strings.sql              |   6 +-
 src/test/regress/sql/tid.sql                  |   4 +-
 src/test/regress/sql/time.sql                 |   4 +-
 src/test/regress/sql/timestamp.sql            |   4 +-
 src/test/regress/sql/timestamptz.sql          |   4 +-
 src/test/regress/sql/timetz.sql               |   4 +-
 src/test/regress/sql/tstypes.sql              |   6 +-
 src/test/regress/sql/uuid.sql                 |   2 +-
 src/test/regress/sql/varchar.sql              |   2 +-
 src/test/regress/sql/xid.sql                  |   8 +-
 src/test/regress/sql/xml.sql                  |   4 +-
 117 files changed, 766 insertions(+), 682 deletions(-)

diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index dc23e5ccc0..47787c50bd 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -344,10 +344,10 @@ SELECT pg_input_is_valid('-1e-700', 'cube');
  f
 (1 row)
 
-SELECT pg_input_error_message('-1e-700', 'cube');
-               pg_input_error_message                
------------------------------------------------------
- "-1e-700" is out of range for type double precision
+SELECT * FROM pg_input_error_info('-1e-700', 'cube');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ "-1e-700" is out of range for type double precision |        |      | 22003
 (1 row)
 
 --
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 384883d16e..eec90d21ee 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -83,7 +83,7 @@ SELECT '-1e-700'::cube AS cube; -- out of range
 SELECT pg_input_is_valid('(1,2)', 'cube');
 SELECT pg_input_is_valid('[(1),]', 'cube');
 SELECT pg_input_is_valid('-1e-700', 'cube');
-SELECT pg_input_error_message('-1e-700', 'cube');
+SELECT * FROM pg_input_error_info('-1e-700', 'cube');
 
 --
 -- Testing building cubes from float8 values
diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index d6faa91867..1836c9acf3 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -265,16 +265,16 @@ select pg_input_is_valid('a=b', 'hstore');
  f
 (1 row)
 
-select pg_input_error_message('a=b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "b" at position 2
+select * from pg_input_error_info('a=b', 'hstore');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ syntax error in hstore, near "b" at position 2 |        |      | 42601
 (1 row)
 
-select pg_input_error_message(' =>b', 'hstore');
-             pg_input_error_message             
-------------------------------------------------
- syntax error in hstore, near "=" at position 1
+select * from pg_input_error_info(' =>b', 'hstore');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ syntax error in hstore, near "=" at position 1 |        |      | 42601
 (1 row)
 
 -- -> operator
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index 15f4f71416..efef91292a 100644
--- a/contrib/hstore/sql/hstore.sql
+++ b/contrib/hstore/sql/hstore.sql
@@ -60,8 +60,8 @@ select 'aa=>"'::hstore;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('a=>b', 'hstore');
 select pg_input_is_valid('a=b', 'hstore');
-select pg_input_error_message('a=b', 'hstore');
-select pg_input_error_message(' =>b', 'hstore');
+select * from pg_input_error_info('a=b', 'hstore');
+select * from pg_input_error_info(' =>b', 'hstore');
 
 
 -- -> operator
diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out
index c953065a5c..6abb17e2e5 100644
--- a/contrib/intarray/expected/_int.out
+++ b/contrib/intarray/expected/_int.out
@@ -401,16 +401,20 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 -- test non-error-throwing input
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
-      AS a(str);
-    query_int    | ok |    errmsg    
------------------+----+--------------
- 1&(2&(4&(5|6))) | t  | 
- 1#(2&(4&(5&6))) | f  | syntax error
- foo             | f  | syntax error
+      AS a(str),
+     LATERAL pg_input_error_info(a.str, 'query_int') as errinfo;
+    query_int    | ok | sql_error_code |   message    | detail | hint 
+-----------------+----+----------------+--------------+--------+------
+ 1&(2&(4&(5|6))) | t  |                |              |        | 
+ 1#(2&(4&(5&6))) | f  | 42601          | syntax error |        | 
+ foo             | f  | 42601          | syntax error |        | 
 (3 rows)
 
 CREATE TABLE test__int( a int[] );
diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql
index 4c9ba4c1fb..d9d987bdb1 100644
--- a/contrib/intarray/sql/_int.sql
+++ b/contrib/intarray/sql/_int.sql
@@ -79,11 +79,15 @@ SELECT '1&(2&(4&(5|!6)))'::query_int;
 
 SELECT str as "query_int",
        pg_input_is_valid(str,'query_int') as ok,
-       pg_input_error_message(str,'query_int') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('1&(2&(4&(5|6)))'),
              ('1#(2&(4&(5&6)))'),
              ('foo'))
-      AS a(str);
+      AS a(str),
+     LATERAL pg_input_error_info(a.str, 'query_int') as errinfo;
 
 
 
diff --git a/contrib/isn/expected/isn.out b/contrib/isn/expected/isn.out
index 72171b2790..2f05b7eb86 100644
--- a/contrib/isn/expected/isn.out
+++ b/contrib/isn/expected/isn.out
@@ -263,16 +263,20 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
-      AS a(str,typ);
-      isn      | type  | ok |                         errmsg                         
----------------+-------+----+--------------------------------------------------------
- 9780123456786 | UPC   | f  | cannot cast ISBN to UPC for number: "9780123456786"
- postgresql... | EAN13 | f  | invalid input syntax for EAN13 number: "postgresql..."
- 9771234567003 | ISSN  | t  | 
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
+      isn      | type  | ok | sql_error_code |                        message                         | detail | hint 
+---------------+-------+----+----------------+--------------------------------------------------------+--------+------
+ 9780123456786 | UPC   | f  | 22P02          | cannot cast ISBN to UPC for number: "9780123456786"    |        | 
+ postgresql... | EAN13 | f  | 22P02          | invalid input syntax for EAN13 number: "postgresql..." |        | 
+ 9771234567003 | ISSN  | t  |                |                                                        |        | 
 (3 rows)
 
 --
diff --git a/contrib/isn/sql/isn.sql b/contrib/isn/sql/isn.sql
index 6426cb42a0..2c2ea077d1 100644
--- a/contrib/isn/sql/isn.sql
+++ b/contrib/isn/sql/isn.sql
@@ -110,11 +110,15 @@ SELECT '12345679'::ISSN = '9771234567003'::EAN13 AS "ok",
 -- test non-error-throwing input API
 SELECT str as isn, typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('9780123456786', 'UPC'),
              ('postgresql...','EAN13'),
              ('9771234567003','ISSN'))
-      AS a(str,typ);
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
 
 --
 -- cleanup
diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index d2a53b9f0c..27122153c7 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -8101,7 +8101,10 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 -- test non-error-throwing input
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
@@ -8110,16 +8113,17 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.3','lquery'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
-      AS a(str,typ);
-     value      |   type    | ok |               errmsg               
-----------------+-----------+----+------------------------------------
- .2.3           | ltree     | f  | ltree syntax error at character 1
- 1.2.           | ltree     | f  | ltree syntax error
- 1.2.3          | ltree     | t  | 
- @.2.3          | lquery    | f  | lquery syntax error at character 1
-  2.3           | lquery    | f  | lquery syntax error at character 1
- 1.2.3          | lquery    | t  | 
- $tree & aWdf@* | ltxtquery | f  | operand syntax error
- !tree & aWdf@* | ltxtquery | t  | 
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
+     value      |   type    | ok | sql_error_code |              message               |          detail          | hint 
+----------------+-----------+----+----------------+------------------------------------+--------------------------+------
+ .2.3           | ltree     | f  | 42601          | ltree syntax error at character 1  |                          | 
+ 1.2.           | ltree     | f  | 42601          | ltree syntax error                 | Unexpected end of input. | 
+ 1.2.3          | ltree     | t  |                |                                    |                          | 
+ @.2.3          | lquery    | f  | 42601          | lquery syntax error at character 1 |                          | 
+  2.3           | lquery    | f  | 42601          | lquery syntax error at character 1 |                          | 
+ 1.2.3          | lquery    | t  |                |                                    |                          | 
+ $tree & aWdf@* | ltxtquery | f  | 42601          | operand syntax error               |                          | 
+ !tree & aWdf@* | ltxtquery | t  |                |                                    |                          | 
 (8 rows)
 
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index 4a6e6266c3..4623b57f7b 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -393,7 +393,10 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
 
 SELECT str as "value", typ as "type",
        pg_input_is_valid(str,typ) as ok,
-       pg_input_error_message(str,typ) as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.', 'ltree'),
              ('1.2.3','ltree'),
@@ -402,4 +405,5 @@ FROM (VALUES ('.2.3', 'ltree'),
              ('1.2.3','lquery'),
              ('$tree & aWdf@*','ltxtquery'),
              ('!tree & aWdf@*','ltxtquery'))
-      AS a(str,typ);
+      AS a(str,typ),
+     LATERAL pg_input_error_info(a.str, a.typ) as errinfo;
diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out
index 7a06113ed8..cd21139b5a 100644
--- a/contrib/seg/expected/seg.out
+++ b/contrib/seg/expected/seg.out
@@ -1276,20 +1276,24 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 -- test non error throwing API
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
                   'ABC',
                   '1 e7',
-                  '1e700']) str;
-   seg    | ok |                errmsg                 
-----------+----+---------------------------------------
- -1 .. 1  | t  | 
- 100(+-)1 | t  | 
-          | f  | bad seg representation
- ABC      | f  | bad seg representation
- 1 e7     | f  | bad seg representation
- 1e700    | f  | "1e700" is out of range for type real
+                  '1e700']) str,
+     LATERAL pg_input_error_info(str, 'seg') as errinfo;
+   seg    | ok | sql_error_code |                message                |            detail            | hint 
+----------+----+----------------+---------------------------------------+------------------------------+------
+ -1 .. 1  | t  |                |                                       |                              | 
+ 100(+-)1 | t  |                |                                       |                              | 
+          | f  | 42601          | bad seg representation                | syntax error at end of input | 
+ ABC      | f  | 42601          | bad seg representation                | syntax error at or near "A"  | 
+ 1 e7     | f  | 42601          | bad seg representation                | syntax error at or near "e"  | 
+ 1e700    | f  | 22003          | "1e700" is out of range for type real |                              | 
 (6 rows)
 
diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql
index b9a5d05d09..c30f1f6bef 100644
--- a/contrib/seg/sql/seg.sql
+++ b/contrib/seg/sql/seg.sql
@@ -244,10 +244,14 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 
 SELECT str as seg,
        pg_input_is_valid(str,'seg') as ok,
-       pg_input_error_message(str,'seg') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['-1 .. 1'::text,
                   '100(+-)1',
                   '',
                   'ABC',
                   '1 e7',
-                  '1e700']) str;
+                  '1e700']) str,
+     LATERAL pg_input_error_info(str, 'seg') as errinfo;
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0cbdf63632..97b3f1c1a6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24775,19 +24775,23 @@ SELECT collation for ('foo' COLLATE "de_DE");
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
-         <primary>pg_input_error_message</primary>
+         <primary>pg_input_error_info</primary>
         </indexterm>
-        <function>pg_input_error_message</function> (
+        <function>pg_input_error_info</function> (
           <parameter>string</parameter> <type>text</type>,
           <parameter>type</parameter> <type>text</type>
         )
-        <returnvalue>text</returnvalue>
+        <returnvalue>record</returnvalue>
+        ( <parameter>message</parameter> <type>text</type>,
+        <parameter>detail</parameter> <type>text</type>,
+        <parameter>hint</parameter> <type>text</type>,
+        <parameter>sql_error_code</parameter> <type>text</type> )
        </para>
        <para>
         Tests whether the given <parameter>string</parameter> is valid
-        input for the specified data type; if not, return the error
-        message that would have been thrown.  If the input is valid, the
-        result is NULL.  The inputs are the same as
+        input for the specified data type; if not, return the details of
+        the error would have been thrown.  If the input is valid, the
+        results are NULL.  The inputs are the same as
         for <function>pg_input_is_valid</function>.
        </para>
        <para>
@@ -24798,12 +24802,17 @@ SELECT collation for ('foo' COLLATE "de_DE");
         directly.
         </para>
         <para>
-         <literal>pg_input_error_message('42000000000', 'integer')</literal>
-         <returnvalue>value "42000000000" is out of range for type integer</returnvalue>
-        </para>
-        <para>
-         <literal>pg_input_error_message('1234.567', 'numeric(7,4)')</literal>
-         <returnvalue>numeric field overflow</returnvalue>
+<programlisting>
+SELECT * FROM pg_input_error_info('42000000000', 'integer');
+                       message                        | detail | hint | sql_error_code
+------------------------------------------------------+--------+------+----------------
+ value "42000000000" is out of range for type integer |        |      | 22003
+
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
+</programlisting>
        </para></entry>
       </row>
      </tbody>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index f95256efd3..182d16cdcd 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -660,32 +660,58 @@ pg_input_is_valid(PG_FUNCTION_ARGS)
 }
 
 /*
- * pg_input_error_message - test whether string is valid input for datatype.
+ * pg_input_error_info - test whether string is valid input for datatype.
  *
- * Returns NULL if OK, else the primary message string from the error.
+ * Returns NULL if OK, else the primary message, detail message, hint message,
+ * and sql error code from the error.
  *
  * This will only work usefully if the datatype's input function has been
  * updated to return "soft" errors via errsave/ereturn.
  */
 Datum
-pg_input_error_message(PG_FUNCTION_ARGS)
+pg_input_error_info(PG_FUNCTION_ARGS)
 {
 	text	   *txt = PG_GETARG_TEXT_PP(0);
 	text	   *typname = PG_GETARG_TEXT_PP(1);
 	ErrorSaveContext escontext = {T_ErrorSaveContext};
+	TupleDesc   tupdesc;
+	Datum       values[4];
+	bool        isnull[4];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
 	/* Enable details_wanted */
 	escontext.details_wanted = true;
 
 	if (pg_input_is_valid_common(fcinfo, txt, typname,
 								 &escontext))
-		PG_RETURN_NULL();
+		memset(isnull, true, sizeof(isnull));
+	else
+	{
+		Assert(escontext.error_occurred);
+		Assert(escontext.error_data != NULL);
+		Assert(escontext.error_data->message != NULL);
+
+		memset(isnull, false, sizeof(isnull));
+
+		values[0] = CStringGetTextDatum(escontext.error_data->message);
 
-	Assert(escontext.error_occurred);
-	Assert(escontext.error_data != NULL);
-	Assert(escontext.error_data->message != NULL);
+		if (escontext.error_data->detail != NULL)
+			values[1] = CStringGetTextDatum(escontext.error_data->detail);
+		else
+			isnull[1] = true;
+
+		if (escontext.error_data->hint != NULL)
+			values[2] = CStringGetTextDatum(escontext.error_data->hint);
+		else
+			isnull[2] = true;
+
+		values[3] = CStringGetTextDatum(
+			unpack_sql_state(escontext.error_data->sqlerrcode));
+	}
 
-	PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /* Common subroutine for the above */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e2a7642a2b..505595620e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7118,9 +7118,13 @@
   proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool',
   proargtypes => 'text text', prosrc => 'pg_input_is_valid' },
 { oid => '8051',
-  descr => 'get error message if string is not valid input for data type',
-  proname => 'pg_input_error_message', provolatile => 's', prorettype => 'text',
-  proargtypes => 'text text', prosrc => 'pg_input_error_message' },
+  descr => 'get error details if string is not valid input for data type',
+  proname => 'pg_input_error_info', provolatile => 's', prorettype => 'record',
+  proargtypes => 'text text',
+  proallargtypes => '{text,text,text,text,text,text}',
+  proargmodes => '{i,i,o,o,o,o}',
+  proargnames => '{value,type_name,message,detail,hint,sql_error_code}',
+  prosrc => 'pg_input_error_info' },
 
 { oid => '1268',
   descr => 'parse qualified identifier to array of identifiers',
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index a2f9d7ed16..0ff54a18de 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -201,10 +201,10 @@ SELECT pg_input_is_valid('{1,zed}', 'integer[]');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+SELECT * FROM pg_input_error_info('{1,zed}', 'integer[]');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 -- test mixed slice/scalar subscripting
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 209044713c..98c2655039 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -753,10 +753,10 @@ SELECT pg_input_is_valid('01010001', 'bit(10)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010001', 'bit(10)');
-             pg_input_error_message              
--------------------------------------------------
- bit string length 8 does not match type bit(10)
+SELECT * FROM pg_input_error_info('01010001', 'bit(10)');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ bit string length 8 does not match type bit(10) |        |      | 22026
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
@@ -765,10 +765,10 @@ SELECT pg_input_is_valid('01010Z01', 'bit(8)');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT * FROM pg_input_error_info('01010Z01', 'bit(8)');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ "Z" is not a valid binary digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
@@ -777,10 +777,10 @@ SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT * FROM pg_input_error_info('x01010Z01', 'bit(32)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ "Z" is not a valid hexadecimal digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
@@ -789,10 +789,10 @@ SELECT pg_input_is_valid('01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('01010Z01', 'varbit');
-     pg_input_error_message      
----------------------------------
- "Z" is not a valid binary digit
+SELECT * FROM pg_input_error_info('01010Z01', 'varbit');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ "Z" is not a valid binary digit |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
@@ -801,9 +801,9 @@ SELECT pg_input_is_valid('x01010Z01', 'varbit');
  f
 (1 row)
 
-SELECT pg_input_error_message('x01010Z01', 'varbit');
-        pg_input_error_message        
---------------------------------------
- "Z" is not a valid hexadecimal digit
+SELECT * FROM pg_input_error_info('x01010Z01', 'varbit');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ "Z" is not a valid hexadecimal digit |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/boolean.out b/src/test/regress/expected/boolean.out
index 977124b20b..ee9c244bf8 100644
--- a/src/test/regress/expected/boolean.out
+++ b/src/test/regress/expected/boolean.out
@@ -155,10 +155,10 @@ SELECT pg_input_is_valid('asdf', 'bool');
  f
 (1 row)
 
-SELECT pg_input_error_message('junk', 'bool');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type boolean: "junk"
+SELECT * FROM pg_input_error_info('junk', 'bool');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type boolean: "junk" |        |      | 22P02
 (1 row)
 
 -- and, or, not in qualifications
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 0d70194def..8c9e9e3935 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -646,10 +646,10 @@ SELECT pg_input_is_valid('200', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('200', 'box');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type box: "200"
+SELECT * FROM pg_input_error_info('200', 'box');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type box: "200" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
@@ -658,9 +658,9 @@ SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
  f
 (1 row)
 
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-                   pg_input_error_message                    
--------------------------------------------------------------
- invalid input syntax for type box: "((200,300),(500, xyz))"
+SELECT * FROM pg_input_error_info('((200,300),(500, xyz))', 'box');
+                           message                           | detail | hint | sql_error_code 
+-------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type box: "((200,300),(500, xyz))" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/char.out b/src/test/regress/expected/char.out
index 199001b2fe..4df596d111 100644
--- a/src/test/regress/expected/char.out
+++ b/src/test/regress/expected/char.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_1.out b/src/test/regress/expected/char_1.out
index 3dcb0daa0d..3add81e9f0 100644
--- a/src/test/regress/expected/char_1.out
+++ b/src/test/regress/expected/char_1.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/char_2.out b/src/test/regress/expected/char_2.out
index dd5d34fe8d..ebde0f3e59 100644
--- a/src/test/regress/expected/char_2.out
+++ b/src/test/regress/expected/char_2.out
@@ -132,10 +132,10 @@ SELECT pg_input_is_valid('abcde', 'char(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'char(4)');
-        pg_input_error_message        
---------------------------------------
- value too long for type character(4)
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
+               message                | detail | hint | sql_error_code 
+--------------------------------------+--------+------+----------------
+ value too long for type character(4) |        |      | 22001
 (1 row)
 
 --
diff --git a/src/test/regress/expected/date.out b/src/test/regress/expected/date.out
index c0dec448e1..f5949f3d17 100644
--- a/src/test/regress/expected/date.out
+++ b/src/test/regress/expected/date.out
@@ -859,16 +859,16 @@ SELECT pg_input_is_valid('6874898-01-01', 'date');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'date');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type date: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'date');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type date: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('6874898-01-01', 'date');
-       pg_input_error_message       
-------------------------------------
- date out of range: "6874898-01-01"
+SELECT * FROM pg_input_error_info('6874898-01-01', 'date');
+              message               | detail | hint | sql_error_code 
+------------------------------------+--------+------+----------------
+ date out of range: "6874898-01-01" |        |      | 22008
 (1 row)
 
 RESET datestyle;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 25f6bb9e1f..b7937fb3bc 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -108,32 +108,32 @@ select pg_input_is_valid('-1', 'positiveint');
  f
 (1 row)
 
-select pg_input_error_message('junk', 'positiveint');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type integer: "junk"
+select * from pg_input_error_info('junk', 'positiveint');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "junk" |        |      | 22P02
 (1 row)
 
-select pg_input_error_message('-1', 'positiveint');
-                           pg_input_error_message                           
-----------------------------------------------------------------------------
- value for domain positiveint violates check constraint "positiveint_check"
+select * from pg_input_error_info('-1', 'positiveint');
+                                  message                                   | detail | hint | sql_error_code 
+----------------------------------------------------------------------------+--------+------+----------------
+ value for domain positiveint violates check constraint "positiveint_check" |        |      | 23514
 (1 row)
 
-select pg_input_error_message('junk', 'weirdfloat');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type double precision: "junk"
+select * from pg_input_error_info('junk', 'weirdfloat');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type double precision: "junk" |        |      | 22P02
 (1 row)
 
-select pg_input_error_message('0.01', 'weirdfloat');
-                          pg_input_error_message                          
---------------------------------------------------------------------------
- value for domain weirdfloat violates check constraint "weirdfloat_check"
+select * from pg_input_error_info('0.01', 'weirdfloat');
+                                 message                                  | detail | hint | sql_error_code 
+--------------------------------------------------------------------------+--------+------+----------------
+ value for domain weirdfloat violates check constraint "weirdfloat_check" |        |      | 23514
 (1 row)
 
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select * from pg_input_error_info('0', 'weirdfloat');
 ERROR:  division by zero
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out
index 4b45fcf8f0..01159688e5 100644
--- a/src/test/regress/expected/enum.out
+++ b/src/test/regress/expected/enum.out
@@ -37,18 +37,21 @@ SELECT pg_input_is_valid('mauve', 'rainbow');
  f
 (1 row)
 
-SELECT pg_input_error_message('mauve', 'rainbow');
-            pg_input_error_message             
------------------------------------------------
- invalid input value for enum rainbow: "mauve"
+SELECT * FROM pg_input_error_info('mauve', 'rainbow');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input value for enum rainbow: "mauve" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
-                                                                                                                                          pg_input_error_message                                                                                                                                          
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
-(1 row)
+\x
+SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
+-[ RECORD 1 ]--+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+message        | invalid input value for enum rainbow: "too_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_longtoo_long"
+detail         | 
+hint           | 
+sql_error_code | 22P02
 
+\x
 --
 -- adding new values
 --
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
index 24fde6cc9f..a427231627 100644
--- a/src/test/regress/expected/float4-misrounded-input.out
+++ b/src/test/regress/expected/float4-misrounded-input.out
@@ -100,10 +100,10 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+SELECT * FROM pg_input_error_info('1e400', 'float4');
+                message                | detail | hint | sql_error_code 
+---------------------------------------+--------+------+----------------
+ "1e400" is out of range for type real |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 1d7090a90d..65ee82caae 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -100,10 +100,10 @@ SELECT pg_input_is_valid('1e400', 'float4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400', 'float4');
-        pg_input_error_message         
----------------------------------------
- "1e400" is out of range for type real
+SELECT * FROM pg_input_error_info('1e400', 'float4');
+                message                | detail | hint | sql_error_code 
+---------------------------------------+--------+------+----------------
+ "1e400" is out of range for type real |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 2b25784f7f..c98407ef0a 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('1e4000', 'float8');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e4000', 'float8');
-               pg_input_error_message               
-----------------------------------------------------
- "1e4000" is out of range for type double precision
+SELECT * FROM pg_input_error_info('1e4000', 'float8');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ "1e4000" is out of range for type double precision |        |      | 22003
 (1 row)
 
 -- special inputs
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 291cacdf4f..8be694f46b 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5302,10 +5302,10 @@ SELECT pg_input_is_valid('(1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,', 'circle');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type circle: "1,"
+SELECT * FROM pg_input_error_info('1,', 'circle');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type circle: "1," |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
@@ -5314,9 +5314,9 @@ SELECT pg_input_is_valid('(1,2),-1', 'circle');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,2),-1', 'circle');
-              pg_input_error_message              
---------------------------------------------------
- invalid input syntax for type circle: "(1,2),-1"
+SELECT * FROM pg_input_error_info('(1,2),-1', 'circle');
+                     message                      | detail | hint | sql_error_code 
+--------------------------------------------------+--------+------+----------------
+ invalid input syntax for type circle: "(1,2),-1" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index c9f466ac1d..b6895d9ced 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1063,10 +1063,10 @@ SELECT pg_input_is_valid('1234', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'cidr');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type cidr: "1234"
+SELECT * FROM pg_input_error_info('1234', 'cidr');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type cidr: "1234" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
@@ -1075,10 +1075,10 @@ SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
  f
 (1 row)
 
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
-          pg_input_error_message          
-------------------------------------------
- invalid cidr value: "192.168.198.200/24"
+SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr');
+                 message                  |                detail                | hint | sql_error_code 
+------------------------------------------+--------------------------------------+------+----------------
+ invalid cidr value: "192.168.198.200/24" | Value has bits set to right of mask. |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('1234', 'inet');
@@ -1087,9 +1087,9 @@ SELECT pg_input_is_valid('1234', 'inet');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234', 'inet');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type inet: "1234"
+SELECT * FROM pg_input_error_info('1234', 'inet');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type inet: "1234" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/int2.out b/src/test/regress/expected/int2.out
index 73b4ee023c..4e03a5faee 100644
--- a/src/test/regress/expected/int2.out
+++ b/src/test/regress/expected/int2.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('50000', 'int2');
  f
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT * FROM pg_input_error_info('50000', 'int2');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "50000" is out of range for type smallint |        |      | 22003
 (1 row)
 
 -- While we're here, check int2vector as well
@@ -77,16 +77,16 @@ SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
  t
 (1 row)
 
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-             pg_input_error_message             
-------------------------------------------------
- invalid input syntax for type smallint: "asdf"
+SELECT * FROM pg_input_error_info('1 asdf', 'int2vector');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ invalid input syntax for type smallint: "asdf" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('50000', 'int2vector');
-             pg_input_error_message              
--------------------------------------------------
- value "50000" is out of range for type smallint
+SELECT * FROM pg_input_error_info('50000', 'int2vector');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "50000" is out of range for type smallint |        |      | 22003
 (1 row)
 
 SELECT * FROM INT2_TBL AS f(a, b);
diff --git a/src/test/regress/expected/int4.out b/src/test/regress/expected/int4.out
index 9c20574ca5..b1a15888ef 100644
--- a/src/test/regress/expected/int4.out
+++ b/src/test/regress/expected/int4.out
@@ -64,10 +64,10 @@ SELECT pg_input_is_valid('1000000000000', 'int4');
  f
 (1 row)
 
-SELECT pg_input_error_message('1000000000000', 'int4');
-                 pg_input_error_message                 
---------------------------------------------------------
- value "1000000000000" is out of range for type integer
+SELECT * FROM pg_input_error_info('1000000000000', 'int4');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ value "1000000000000" is out of range for type integer |        |      | 22003
 (1 row)
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
diff --git a/src/test/regress/expected/int8.out b/src/test/regress/expected/int8.out
index d9dca64e88..9542d622ba 100644
--- a/src/test/regress/expected/int8.out
+++ b/src/test/regress/expected/int8.out
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('10000000000000000000', 'int8');
  f
 (1 row)
 
-SELECT pg_input_error_message('10000000000000000000', 'int8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "10000000000000000000" is out of range for type bigint
+SELECT * FROM pg_input_error_info('10000000000000000000', 'int8');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "10000000000000000000" is out of range for type bigint |        |      | 22003
 (1 row)
 
 -- int8/int8 cmp
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index a154840c85..28b71d9681 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -91,16 +91,16 @@ SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'interval');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type interval: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'interval');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type interval: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type interval: "@ 30 eons ago"
+SELECT * FROM pg_input_error_info('@ 30 eons ago', 'interval');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type interval: "@ 30 eons ago" |        |      | 22007
 (1 row)
 
 -- test interval operators
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index af96ce4180..56dba9d6e2 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -333,10 +333,10 @@ select pg_input_is_valid('{"a":true', 'json');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'json');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select * from pg_input_error_info('{"a":true', 'json');
+              message               |                detail                | hint | sql_error_code 
+------------------------------------+--------------------------------------+------+----------------
+ invalid input syntax for type json | The input string ended unexpectedly. |      | 22P02
 (1 row)
 
 --constructors
diff --git a/src/test/regress/expected/json_encoding.out b/src/test/regress/expected/json_encoding.out
index 083621fb21..f18ba9ebb2 100644
--- a/src/test/regress/expected/json_encoding.out
+++ b/src/test/regress/expected/json_encoding.out
@@ -261,9 +261,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
- pg_input_error_message 
-------------------------
- 
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+ message | detail | hint | sql_error_code 
+---------+--------+------+----------------
+         |        |      | 
 (1 row)
 
diff --git a/src/test/regress/expected/json_encoding_1.out b/src/test/regress/expected/json_encoding_1.out
index 021d226f8d..77bdaf63a1 100644
--- a/src/test/regress/expected/json_encoding_1.out
+++ b/src/test/regress/expected/json_encoding_1.out
@@ -257,9 +257,9 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 (1 row)
 
 -- soft error for input-time failure
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
-       pg_input_error_message        
--------------------------------------
- unsupported Unicode escape sequence
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+               message               |                                      detail                                      | hint | sql_error_code 
+-------------------------------------+----------------------------------------------------------------------------------+------+----------------
+ unsupported Unicode escape sequence | Unicode escape value could not be translated to the server's encoding SQL_ASCII. |      | 22P05
 (1 row)
 
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index d3248aa0fd..4a16d0dbaf 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -323,16 +323,16 @@ select pg_input_is_valid('{"a":true', 'jsonb');
  f
 (1 row)
 
-select pg_input_error_message('{"a":true', 'jsonb');
-       pg_input_error_message       
-------------------------------------
- invalid input syntax for type json
+select * from pg_input_error_info('{"a":true', 'jsonb');
+              message               |                detail                | hint | sql_error_code 
+------------------------------------+--------------------------------------+------+----------------
+ invalid input syntax for type json | The input string ended unexpectedly. |      | 22P02
 (1 row)
 
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+select * from pg_input_error_info('{"a":1e1000000}', 'jsonb');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ value overflows numeric format |        |      | 22003
 (1 row)
 
 -- make sure jsonb is passed through json generators without being escaped
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index ca0cdf1ab2..f866fb474f 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -1035,18 +1035,22 @@ select '1?(2>3)'::jsonpath;
 -- test non-error-throwing API
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
                   '00',
-                  '1a']) str;
-                 jsonpath                  | ok |                                errmsg                                 
--------------------------------------------+----+-----------------------------------------------------------------------
- $ ? (@ like_regex "pattern" flag "smixq") | t  | 
- $ ? (@ like_regex "pattern" flag "a")     | f  | invalid input syntax for type jsonpath
- @ + 1                                     | f  | @ is not allowed in root expressions
- 00                                        | f  | trailing junk after numeric literal at or near "00" of jsonpath input
- 1a                                        | f  | trailing junk after numeric literal at or near "1a" of jsonpath input
+                  '1a']) str,
+     LATERAL pg_input_error_info(str, 'jsonpath') as errinfo;
+                 jsonpath                  | ok | sql_error_code |                                message                                |                          detail                          | hint 
+-------------------------------------------+----+----------------+-----------------------------------------------------------------------+----------------------------------------------------------+------
+ $ ? (@ like_regex "pattern" flag "smixq") | t  |                |                                                                       |                                                          | 
+ $ ? (@ like_regex "pattern" flag "a")     | f  | 42601          | invalid input syntax for type jsonpath                                | Unrecognized flag character "a" in LIKE_REGEX predicate. | 
+ @ + 1                                     | f  | 42601          | @ is not allowed in root expressions                                  |                                                          | 
+ 00                                        | f  | 42601          | trailing junk after numeric literal at or near "00" of jsonpath input |                                                          | 
+ 1a                                        | f  | 42601          | trailing junk after numeric literal at or near "1a" of jsonpath input |                                                          | 
 (5 rows)
 
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index 6baea8fdbd..e7d4332877 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -92,10 +92,10 @@ SELECT pg_input_is_valid('{1, 1}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1}', 'line');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type line: "{1, 1}"
+SELECT * FROM pg_input_error_info('{1, 1}', 'line');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type line: "{1, 1}" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
@@ -104,10 +104,10 @@ SELECT pg_input_is_valid('{0, 0, 0}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid line specification: A and B cannot both be zero
+SELECT * FROM pg_input_error_info('{0, 0, 0}', 'line');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid line specification: A and B cannot both be zero |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
@@ -116,10 +116,10 @@ SELECT pg_input_is_valid('{1, 1, a}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, a}', 'line');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type line: "{1, 1, a}"
+SELECT * FROM pg_input_error_info('{1, 1, a}', 'line');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ invalid input syntax for type line: "{1, 1, a}" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
@@ -128,10 +128,10 @@ SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('{1, 1, 1e400}', 'line');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
@@ -140,9 +140,9 @@ SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('(1, 1), (1, 1e400)', 'line');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index afb323fe04..c0375ac3f3 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -49,9 +49,9 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type lseg: "[(1,2),(3)]"
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'lseg');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type lseg: "[(1,2),(3)]" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index cb646af79b..8d5b22195a 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -165,10 +165,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
-                   pg_input_error_message                   
-------------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
+                          message                           | detail | hint | sql_error_code 
+------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
@@ -177,9 +177,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type macaddr: "08:00:2b:01:02:"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index bf681988f8..460e8506b6 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -359,10 +359,10 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
@@ -371,9 +371,9 @@ SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
  f
 (1 row)
 
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
+                             message                             | detail | hint | sql_error_code 
+-----------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 46b2eab51a..7fd4e31804 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -338,10 +338,10 @@ SELECT pg_input_is_valid('\x0001', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('\x0001', 'money');
-            pg_input_error_message             
------------------------------------------------
- invalid input syntax for type money: "\x0001"
+SELECT * FROM pg_input_error_info('\x0001', 'money');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ invalid input syntax for type money: "\x0001" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
@@ -350,10 +350,10 @@ SELECT pg_input_is_valid('192233720368547758.07', 'money');
  f
 (1 row)
 
-SELECT pg_input_error_message('192233720368547758.07', 'money');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "192233720368547758.07" is out of range for type money
+SELECT * FROM pg_input_error_info('192233720368547758.07', 'money');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "192233720368547758.07" is out of range for type money |        |      | 22003
 (1 row)
 
 -- documented minimums and maximums
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index e70896b754..a0cb875492 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -287,10 +287,10 @@ select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
-            pg_input_error_message             
------------------------------------------------
- malformed multirange literal: "{[1,2], [4,5]"
+select * from pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
+                    message                    |          detail          | hint | sql_error_code 
+-----------------------------------------------+--------------------------+------+----------------
+ malformed multirange literal: "{[1,2], [4,5]" | Unexpected end of input. |      | 22P02
 (1 row)
 
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
@@ -299,10 +299,10 @@ select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
  f
 (1 row)
 
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select * from pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 56a3f3630a..2ac2c99b19 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2312,10 +2312,10 @@ SELECT pg_input_is_valid('1e400000', 'numeric');
  f
 (1 row)
 
-SELECT pg_input_error_message('1e400000', 'numeric');
-     pg_input_error_message     
---------------------------------
- value overflows numeric format
+SELECT * FROM pg_input_error_info('1e400000', 'numeric');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ value overflows numeric format |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
@@ -2330,16 +2330,16 @@ SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
- pg_input_error_message 
-------------------------
- numeric field overflow
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+        message         |                                      detail                                       | hint | sql_error_code 
+------------------------+-----------------------------------------------------------------------------------+------+----------------
+ numeric field overflow | A field with precision 7, scale 4 must round to an absolute value less than 10^3. |      | 22003
 (1 row)
 
-SELECT pg_input_error_message('0x1234.567', 'numeric');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type numeric: "0x1234.567"
+SELECT * FROM pg_input_error_info('0x1234.567', 'numeric');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type numeric: "0x1234.567" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/oid.out b/src/test/regress/expected/oid.out
index b664bab5f9..b80cb47e0c 100644
--- a/src/test/regress/expected/oid.out
+++ b/src/test/regress/expected/oid.out
@@ -78,10 +78,10 @@ SELECT pg_input_is_valid('01XYZ', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('01XYZ', 'oid');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type oid: "01XYZ"
+SELECT * FROM pg_input_error_info('01XYZ', 'oid');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type oid: "01XYZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('9999999999', 'oid');
@@ -90,10 +90,10 @@ SELECT pg_input_is_valid('9999999999', 'oid');
  f
 (1 row)
 
-SELECT pg_input_error_message('9999999999', 'oid');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT * FROM pg_input_error_info('9999999999', 'oid');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "9999999999" is out of range for type oid |        |      | 22003
 (1 row)
 
 -- While we're here, check oidvector as well
@@ -109,10 +109,10 @@ SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type oid: "XYZ"
+SELECT * FROM pg_input_error_info('01 01XYZ', 'oidvector');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type oid: "XYZ" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
@@ -121,10 +121,10 @@ SELECT pg_input_is_valid('01 9999999999', 'oidvector');
  f
 (1 row)
 
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
-             pg_input_error_message              
--------------------------------------------------
- value "9999999999" is out of range for type oid
+SELECT * FROM pg_input_error_info('01 9999999999', 'oidvector');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ value "9999999999" is out of range for type oid |        |      | 22003
 (1 row)
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
diff --git a/src/test/regress/expected/path.out b/src/test/regress/expected/path.out
index 529a5e6fc2..4994641bde 100644
--- a/src/test/regress/expected/path.out
+++ b/src/test/regress/expected/path.out
@@ -87,10 +87,10 @@ SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
-              pg_input_error_message               
----------------------------------------------------
- invalid input syntax for type path: "[(1,2),(3)]"
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'path');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ invalid input syntax for type path: "[(1,2),(3)]" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
@@ -99,9 +99,9 @@ SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
  f
 (1 row)
 
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
-                 pg_input_error_message                  
----------------------------------------------------------
- invalid input syntax for type path: "[(1,2,6),(3,4,6)]"
+SELECT * FROM pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type path: "[(1,2,6),(3,4,6)]" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/pg_lsn.out b/src/test/regress/expected/pg_lsn.out
index 01501f8c9b..b27eec7c01 100644
--- a/src/test/regress/expected/pg_lsn.out
+++ b/src/test/regress/expected/pg_lsn.out
@@ -33,10 +33,10 @@ SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
  f
 (1 row)
 
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
-             pg_input_error_message              
--------------------------------------------------
- invalid input syntax for type pg_lsn: "16AE7F7"
+SELECT * FROM pg_input_error_info('16AE7F7', 'pg_lsn');
+                     message                     | detail | hint | sql_error_code 
+-------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_lsn: "16AE7F7" |        |      | 22P02
 (1 row)
 
 -- Min/Max aggregation
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index a716ceb881..ba508c3ea4 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -470,9 +470,9 @@ SELECT pg_input_is_valid('1,y', 'point');
  f
 (1 row)
 
-SELECT pg_input_error_message('1,y', 'point');
-           pg_input_error_message           
---------------------------------------------
- invalid input syntax for type point: "1,y"
+SELECT * FROM pg_input_error_info('1,y', 'point');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ invalid input syntax for type point: "1,y" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index c7d565ad53..7a9778e70f 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -313,10 +313,10 @@ SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
-                 pg_input_error_message                 
---------------------------------------------------------
- invalid input syntax for type polygon: "(2.0,0.8,0.1)"
+SELECT * FROM pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
+                        message                         | detail | hint | sql_error_code 
+--------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type polygon: "(2.0,0.8,0.1)" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
@@ -325,9 +325,9 @@ SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
  f
 (1 row)
 
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type polygon: "(2.0,xyz)"
+SELECT * FROM pg_input_error_info('(2.0,xyz)', 'polygon');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type polygon: "(2.0,xyz)" |        |      | 22P02
 (1 row)
 
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 95d1e5515f..5496ec8f55 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -2246,10 +2246,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
-     pg_input_error_message      
----------------------------------
- a name must follow the "/" sign
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/', 'aclitem');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ a name must follow the "/" sign |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
@@ -2258,10 +2258,10 @@ SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem')
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-           pg_input_error_message           
---------------------------------------------
- role "regress_no_such_user" does not exist
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ role "regress_no_such_user" does not exist |        |      | 42704
 (1 row)
 
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
@@ -2270,10 +2270,10 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
  f
 (1 row)
 
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm"
+SELECT * FROM pg_input_error_info('regress_priv_user1=rY', 'aclitem');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid mode character: must be one of "arwdDxtXUCTcsAm" |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a3e9e447af..ee02ff0163 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -188,10 +188,10 @@ select pg_input_is_valid('(1,4', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(1,4', 'int4range');
-     pg_input_error_message      
----------------------------------
- malformed range literal: "(1,4"
+select * from pg_input_error_info('(1,4', 'int4range');
+             message             |          detail          | hint | sql_error_code 
+---------------------------------+--------------------------+------+----------------
+ malformed range literal: "(1,4" | Unexpected end of input. |      | 22P02
 (1 row)
 
 select pg_input_is_valid('(4,1)', 'int4range');
@@ -200,10 +200,10 @@ select pg_input_is_valid('(4,1)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,1)', 'int4range');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- range lower bound must be less than or equal to range upper bound
+select * from pg_input_error_info('(4,1)', 'int4range');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ range lower bound must be less than or equal to range upper bound |        |      | 22000
 (1 row)
 
 select pg_input_is_valid('(4,zed)', 'int4range');
@@ -212,10 +212,10 @@ select pg_input_is_valid('(4,zed)', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('(4,zed)', 'int4range');
-            pg_input_error_message            
-----------------------------------------------
- invalid input syntax for type integer: "zed"
+select * from pg_input_error_info('(4,zed)', 'int4range');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ invalid input syntax for type integer: "zed" |        |      | 22P02
 (1 row)
 
 select pg_input_is_valid('[1,2147483647]', 'int4range');
@@ -224,10 +224,10 @@ select pg_input_is_valid('[1,2147483647]', 'int4range');
  f
 (1 row)
 
-select pg_input_error_message('[1,2147483647]', 'int4range');
- pg_input_error_message 
-------------------------
- integer out of range
+select * from pg_input_error_info('[1,2147483647]', 'int4range');
+       message        | detail | hint | sql_error_code 
+----------------------+--------+------+----------------
+ integer out of range |        |      | 22003
 (1 row)
 
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
@@ -236,10 +236,10 @@ select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
  f
 (1 row)
 
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
- pg_input_error_message 
-------------------------
- date out of range
+select * from pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
+      message      | detail | hint | sql_error_code 
+-------------------+--------+------+----------------
+ date out of range |        |      | 22008
 (1 row)
 
 --
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index a034fbb346..a9420850b8 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -448,10 +448,10 @@ SELECT to_regnamespace('foo.bar');
 (1 row)
 
 -- Test soft-error API
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
-            pg_input_error_message             
------------------------------------------------
- relation "ng_catalog.pg_class" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');
+                    message                    | detail | hint | sql_error_code 
+-----------------------------------------------+--------+------+----------------
+ relation "ng_catalog.pg_class" does not exist |        |      | 42P01
 (1 row)
 
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
@@ -460,87 +460,87 @@ SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
  f
 (1 row)
 
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-                  pg_input_error_message                   
------------------------------------------------------------
- text search configuration "no_such_config" does not exist
+SELECT * FROM pg_input_error_info('no_such_config', 'regconfig');
+                          message                          | detail | hint | sql_error_code 
+-----------------------------------------------------------+--------+------+----------------
+ text search configuration "no_such_config" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-                   pg_input_error_message                   
-------------------------------------------------------------
- text search dictionary "no_such_dictionary" does not exist
+SELECT * FROM pg_input_error_info('no_such_dictionary', 'regdictionary');
+                          message                           | detail | hint | sql_error_code 
+------------------------------------------------------------+--------+------+----------------
+ text search dictionary "no_such_dictionary" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-       pg_input_error_message        
--------------------------------------
- schema "nonexistent" does not exist
+SELECT * FROM pg_input_error_info('Nonexistent', 'regnamespace');
+               message               | detail | hint | sql_error_code 
+-------------------------------------+--------+------+----------------
+ schema "nonexistent" does not exist |        |      | 3F000
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-         pg_input_error_message          
------------------------------------------
- operator does not exist: ng_catalog.||/
+SELECT * FROM pg_input_error_info('ng_catalog.||/', 'regoper');
+                 message                 | detail | hint | sql_error_code 
+-----------------------------------------+--------+------+----------------
+ operator does not exist: ng_catalog.||/ |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoper');
-     pg_input_error_message     
---------------------------------
- more than one operator named -
+SELECT * FROM pg_input_error_info('-', 'regoper');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ more than one operator named - |        |      | 42725
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-              pg_input_error_message              
---------------------------------------------------
- operator does not exist: ng_catalog.+(int4,int4)
+SELECT * FROM pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+                     message                      | detail | hint | sql_error_code 
+--------------------------------------------------+--------+------+----------------
+ operator does not exist: ng_catalog.+(int4,int4) |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('-', 'regoperator');
-   pg_input_error_message    
------------------------------
- expected a left parenthesis
+SELECT * FROM pg_input_error_info('-', 'regoperator');
+           message           | detail | hint | sql_error_code 
+-----------------------------+--------+------+----------------
+ expected a left parenthesis |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-          pg_input_error_message          
-------------------------------------------
- function "ng_catalog.now" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.now', 'regproc');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ function "ng_catalog.now" does not exist |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-              pg_input_error_message               
----------------------------------------------------
- function "ng_catalog.abs(numeric)" does not exist
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ function "ng_catalog.abs(numeric)" does not exist |        |      | 42883
 (1 row)
 
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-    pg_input_error_message    
-------------------------------
- expected a right parenthesis
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+           message            | detail | hint | sql_error_code 
+------------------------------+--------+------+----------------
+ expected a right parenthesis |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-           pg_input_error_message           
---------------------------------------------
- role "regress_regrole_test" does not exist
+SELECT * FROM pg_input_error_info('regress_regrole_test', 'regrole');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ role "regress_regrole_test" does not exist |        |      | 42704
 (1 row)
 
-SELECT pg_input_error_message('no_such_type', 'regtype');
-       pg_input_error_message       
-------------------------------------
- type "no_such_type" does not exist
+SELECT * FROM pg_input_error_info('no_such_type', 'regtype');
+              message               | detail | hint | sql_error_code 
+------------------------------------+--------+------+----------------
+ type "no_such_type" does not exist |        |      | 42704
 (1 row)
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
+SELECT * FROM pg_input_error_info('incorrect type name syntax', 'regtype');
 ERROR:  syntax error at or near "type"
-LINE 1: SELECT pg_input_error_message('incorrect type name syntax', ...
+LINE 1: SELECT * FROM pg_input_error_info('incorrect type name synta...
                   ^
 CONTEXT:  invalid type name "incorrect type name syntax"
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT * FROM pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
 ERROR:  invalid NUMERIC type modifier
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
+SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
 ERROR:  improper qualified name (too many dotted names): way.too.many.names
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
 ERROR:  cross-database references are not implemented: no_such_catalog.schema.name
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 801d9e556b..2ee6b1829b 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -88,16 +88,16 @@ SELECT pg_input_is_valid('(1,zed)', 'complex');
  f
 (1 row)
 
-SELECT pg_input_error_message('(1,zed)', 'complex');
-                pg_input_error_message                 
--------------------------------------------------------
- invalid input syntax for type double precision: "zed"
+SELECT * FROM pg_input_error_info('(1,zed)', 'complex');
+                        message                        | detail | hint | sql_error_code 
+-------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type double precision: "zed" |        |      | 22P02
 (1 row)
 
-SELECT pg_input_error_message('(1,1e400)', 'complex');
-              pg_input_error_message               
----------------------------------------------------
- "1e400" is out of range for type double precision
+SELECT * FROM pg_input_error_info('(1,1e400)', 'complex');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ "1e400" is out of range for type double precision |        |      | 22003
 (1 row)
 
 create temp table quadtable(f1 int, q quad);
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index f028c1f10f..403a29ed8c 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -280,22 +280,22 @@ SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
  f
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-             pg_input_error_message             
-------------------------------------------------
- invalid hexadecimal data: odd number of digits
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ invalid hexadecimal data: odd number of digits |        |      | 22023
 (1 row)
 
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-     pg_input_error_message     
---------------------------------
- invalid hexadecimal digit: "x"
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ invalid hexadecimal digit: "x" |        |      | 22023
 (1 row)
 
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
-       pg_input_error_message        
--------------------------------------
- invalid input syntax for type bytea
+SELECT * FROM pg_input_error_info(E'foo\\99bar', 'bytea');
+               message               | detail | hint | sql_error_code 
+-------------------------------------+--------+------+----------------
+ invalid input syntax for type bytea |        |      | 22P02
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out
index ff67ed43f0..083c83a1e1 100644
--- a/src/test/regress/expected/tid.out
+++ b/src/test/regress/expected/tid.out
@@ -24,10 +24,10 @@ SELECT pg_input_is_valid('(0)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0)', 'tid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type tid: "(0)"
+SELECT * FROM pg_input_error_info('(0)', 'tid');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type tid: "(0)" |        |      | 22P02
 (1 row)
 
 SELECT pg_input_is_valid('(0,-1)', 'tid');
@@ -36,10 +36,10 @@ SELECT pg_input_is_valid('(0,-1)', 'tid');
  f
 (1 row)
 
-SELECT pg_input_error_message('(0,-1)', 'tid');
-           pg_input_error_message            
----------------------------------------------
- invalid input syntax for type tid: "(0,-1)"
+SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
+                   message                   | detail | hint | sql_error_code 
+---------------------------------------------+--------+------+----------------
+ invalid input syntax for type tid: "(0,-1)" |        |      | 22P02
 (1 row)
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index a44caededd..4247fae941 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -133,16 +133,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00', 'time');
-             pg_input_error_message             
-------------------------------------------------
- date/time field value out of range: "25:00:00"
+SELECT * FROM pg_input_error_info('25:00:00', 'time');
+                    message                     | detail | hint | sql_error_code 
+------------------------------------------------+--------+------+----------------
+ date/time field value out of range: "25:00:00" |        |      | 22008
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
-                     pg_input_error_message                      
------------------------------------------------------------------
- invalid input syntax for type time: "15:36:39 America/New_York"
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'time');
+                             message                             | detail | hint | sql_error_code 
+-----------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type time: "15:36:39 America/New_York" |        |      | 22007
 (1 row)
 
 --
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index eef2f7001c..c64bcb7c12 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -144,16 +144,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamp');
-               pg_input_error_message               
-----------------------------------------------------
- invalid input syntax for type timestamp: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'timestamp');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type timestamp: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ time zone "nehwon/lankhmar" not recognized |        |      | 22023
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index b85a93a3c2..91d7c1f5cc 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -195,16 +195,16 @@ SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
  f
 (1 row)
 
-SELECT pg_input_error_message('garbage', 'timestamptz');
-                      pg_input_error_message                       
--------------------------------------------------------------------
- invalid input syntax for type timestamp with time zone: "garbage"
+SELECT * FROM pg_input_error_info('garbage', 'timestamptz');
+                              message                              | detail | hint | sql_error_code 
+-------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type timestamp with time zone: "garbage" |        |      | 22007
 (1 row)
 
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-           pg_input_error_message           
---------------------------------------------
- time zone "nehwon/lankhmar" not recognized
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+                  message                   | detail | hint | sql_error_code 
+--------------------------------------------+--------+------+----------------
+ time zone "nehwon/lankhmar" not recognized |        |      | 22023
 (1 row)
 
 -- Check date conversion and date arithmetic
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index 984285663b..be49588b6d 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -150,16 +150,16 @@ SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
  f
 (1 row)
 
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-               pg_input_error_message               
-----------------------------------------------------
- date/time field value out of range: "25:00:00 PDT"
+SELECT * FROM pg_input_error_info('25:00:00 PDT', 'timetz');
+                      message                       | detail | hint | sql_error_code 
+----------------------------------------------------+--------+------+----------------
+ date/time field value out of range: "25:00:00 PDT" |        |      | 22008
 (1 row)
 
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
-                             pg_input_error_message                             
---------------------------------------------------------------------------------
- invalid input syntax for type time with time zone: "15:36:39 America/New_York"
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'timetz');
+                                    message                                     | detail | hint | sql_error_code 
+--------------------------------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type time with time zone: "15:36:39 America/New_York" |        |      | 22007
 (1 row)
 
 --
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index a8785cd708..4cfc3b9dc0 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -102,10 +102,10 @@ SELECT pg_input_is_valid($$''$$, 'tsvector');
  f
 (1 row)
 
-SELECT pg_input_error_message($$''$$, 'tsvector');
-     pg_input_error_message     
---------------------------------
- syntax error in tsvector: "''"
+SELECT * FROM pg_input_error_info($$''$$, 'tsvector');
+            message             | detail | hint | sql_error_code 
+--------------------------------+--------+------+----------------
+ syntax error in tsvector: "''" |        |      | 42601
 (1 row)
 
 --Base tsquery test
@@ -404,16 +404,16 @@ SELECT pg_input_is_valid('foo!', 'tsquery');
  f
 (1 row)
 
-SELECT pg_input_error_message('foo!', 'tsquery');
-     pg_input_error_message      
----------------------------------
- syntax error in tsquery: "foo!"
+SELECT * FROM pg_input_error_info('foo!', 'tsquery');
+             message             | detail | hint | sql_error_code 
+---------------------------------+--------+------+----------------
+ syntax error in tsquery: "foo!" |        |      | 42601
 (1 row)
 
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
-                                pg_input_error_message                                 
----------------------------------------------------------------------------------------
- distance in phrase operator must be an integer value between zero and 16384 inclusive
+SELECT * FROM pg_input_error_info('a <100000> b', 'tsquery');
+                                        message                                        | detail | hint | sql_error_code 
+---------------------------------------------------------------------------------------+--------+------+----------------
+ distance in phrase operator must be an integer value between zero and 16384 inclusive |        |      | 22023
 (1 row)
 
 --comparisons
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 0f47232009..8e7f21910d 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -46,10 +46,10 @@ SELECT pg_input_is_valid('11', 'uuid');
  f
 (1 row)
 
-SELECT pg_input_error_message('11', 'uuid');
-          pg_input_error_message          
-------------------------------------------
- invalid input syntax for type uuid: "11"
+SELECT * FROM pg_input_error_info('11', 'uuid');
+                 message                  | detail | hint | sql_error_code 
+------------------------------------------+--------+------+----------------
+ invalid input syntax for type uuid: "11" |        |      | 22P02
 (1 row)
 
 --inserting three input formats
diff --git a/src/test/regress/expected/varchar.out b/src/test/regress/expected/varchar.out
index 62b683d86f..28863529a6 100644
--- a/src/test/regress/expected/varchar.out
+++ b/src/test/regress/expected/varchar.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_1.out b/src/test/regress/expected/varchar_1.out
index 6690f81c0b..7cb74c752a 100644
--- a/src/test/regress/expected/varchar_1.out
+++ b/src/test/regress/expected/varchar_1.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/varchar_2.out b/src/test/regress/expected/varchar_2.out
index ad8aa7c693..9b154c6ca5 100644
--- a/src/test/regress/expected/varchar_2.out
+++ b/src/test/regress/expected/varchar_2.out
@@ -124,9 +124,9 @@ SELECT pg_input_is_valid('abcde', 'varchar(4)');
  f
 (1 row)
 
-SELECT pg_input_error_message('abcde', 'varchar(4)');
-            pg_input_error_message            
-----------------------------------------------
- value too long for type character varying(4)
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
+                   message                    | detail | hint | sql_error_code 
+----------------------------------------------+--------+------+----------------
+ value too long for type character varying(4) |        |      | 22001
 (1 row)
 
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index e62f701943..835077e9d5 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -43,10 +43,10 @@ SELECT pg_input_is_valid('asdf', 'xid');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffff', 'xid');
-              pg_input_error_message               
----------------------------------------------------
- value "0xffffffffff" is out of range for type xid
+SELECT * FROM pg_input_error_info('0xffffffffff', 'xid');
+                      message                      | detail | hint | sql_error_code 
+---------------------------------------------------+--------+------+----------------
+ value "0xffffffffff" is out of range for type xid |        |      | 22003
 (1 row)
 
 SELECT pg_input_is_valid('42', 'xid8');
@@ -61,10 +61,10 @@ SELECT pg_input_is_valid('asdf', 'xid8');
  f
 (1 row)
 
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
-                    pg_input_error_message                    
---------------------------------------------------------------
- value "0xffffffffffffffffffff" is out of range for type xid8
+SELECT * FROM pg_input_error_info('0xffffffffffffffffffff', 'xid8');
+                           message                            | detail | hint | sql_error_code 
+--------------------------------------------------------------+--------+------+----------------
+ value "0xffffffffffffffffffff" is out of range for type xid8 |        |      | 22003
 (1 row)
 
 -- equality
@@ -223,10 +223,10 @@ select pg_input_is_valid('31:12:', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('31:12:', 'pg_snapshot');
-               pg_input_error_message                
------------------------------------------------------
- invalid input syntax for type pg_snapshot: "31:12:"
+select * from pg_input_error_info('31:12:', 'pg_snapshot');
+                       message                       | detail | hint | sql_error_code 
+-----------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_snapshot: "31:12:" |        |      | 22P02
 (1 row)
 
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
@@ -235,10 +235,10 @@ select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
  f
 (1 row)
 
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
-                  pg_input_error_message                  
-----------------------------------------------------------
- invalid input syntax for type pg_snapshot: "12:16:14,13"
+select * from pg_input_error_info('12:16:14,13', 'pg_snapshot');
+                         message                          | detail | hint | sql_error_code 
+----------------------------------------------------------+--------+------+----------------
+ invalid input syntax for type pg_snapshot: "12:16:14,13" |        |      | 22P02
 (1 row)
 
 create temp table snapshot_test (
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..ad852dc2f7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -31,9 +31,9 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
-------------------------
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message       
+---------------------
  invalid XML content
 (1 row)
 
@@ -43,8 +43,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 378b412db0..70fe34a04f 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -29,13 +29,13 @@ DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlcomment('test');
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 42055c5003..e01f431219 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -29,8 +29,8 @@ SELECT pg_input_is_valid('<value>one</', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<value>one</', 'xml');
- pg_input_error_message 
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
+       message          
 ------------------------
  invalid XML content
 (1 row)
@@ -41,8 +41,8 @@ SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
  f
 (1 row)
 
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-            pg_input_error_message            
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+                   message                    
 ----------------------------------------------
  invalid XML content: invalid XML declaration
 (1 row)
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 38e8dd440b..6ea4dba9f1 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -117,7 +117,7 @@ SELECT a,b,c FROM arrtest;
 SELECT pg_input_is_valid('{1,2,3}', 'integer[]');
 SELECT pg_input_is_valid('{1,2', 'integer[]');
 SELECT pg_input_is_valid('{1,zed}', 'integer[]');
-SELECT pg_input_error_message('{1,zed}', 'integer[]');
+SELECT * FROM pg_input_error_info('{1,zed}', 'integer[]');
 
 -- test mixed slice/scalar subscripting
 select '{{1,2,3},{4,5,6},{7,8,9}}'::int[];
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 8814249c2a..2cd550d27e 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -232,13 +232,13 @@ TABLE bit_defaults;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('01010001', 'bit(10)');
-SELECT pg_input_error_message('01010001', 'bit(10)');
+SELECT * FROM pg_input_error_info('01010001', 'bit(10)');
 SELECT pg_input_is_valid('01010Z01', 'bit(8)');
-SELECT pg_input_error_message('01010Z01', 'bit(8)');
+SELECT * FROM pg_input_error_info('01010Z01', 'bit(8)');
 SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
-SELECT pg_input_error_message('x01010Z01', 'bit(32)');
+SELECT * FROM pg_input_error_info('x01010Z01', 'bit(32)');
 
 SELECT pg_input_is_valid('01010Z01', 'varbit');
-SELECT pg_input_error_message('01010Z01', 'varbit');
+SELECT * FROM pg_input_error_info('01010Z01', 'varbit');
 SELECT pg_input_is_valid('x01010Z01', 'varbit');
-SELECT pg_input_error_message('x01010Z01', 'varbit');
+SELECT * FROM pg_input_error_info('x01010Z01', 'varbit');
diff --git a/src/test/regress/sql/boolean.sql b/src/test/regress/sql/boolean.sql
index dfaa55dd0f..bc9937d692 100644
--- a/src/test/regress/sql/boolean.sql
+++ b/src/test/regress/sql/boolean.sql
@@ -65,7 +65,7 @@ SELECT bool '' AS error;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('true', 'bool');
 SELECT pg_input_is_valid('asdf', 'bool');
-SELECT pg_input_error_message('junk', 'bool');
+SELECT * FROM pg_input_error_info('junk', 'bool');
 
 -- and, or, not in qualifications
 
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index 02e100391b..2d0868e889 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -284,6 +284,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('200', 'box');
-SELECT pg_input_error_message('200', 'box');
+SELECT * FROM pg_input_error_info('200', 'box');
 SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
-SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
+SELECT * FROM pg_input_error_info('((200,300),(500, xyz))', 'box');
diff --git a/src/test/regress/sql/char.sql b/src/test/regress/sql/char.sql
index 8aa43b0fb8..fdda9d1929 100644
--- a/src/test/regress/sql/char.sql
+++ b/src/test/regress/sql/char.sql
@@ -75,7 +75,7 @@ SELECT * FROM CHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'char(4)');
 SELECT pg_input_is_valid('abcde', 'char(4)');
-SELECT pg_input_error_message('abcde', 'char(4)');
+SELECT * FROM pg_input_error_info('abcde', 'char(4)');
 
 --
 -- Also test "char", which is an ad-hoc one-byte type.  It can only
diff --git a/src/test/regress/sql/date.sql b/src/test/regress/sql/date.sql
index 89982dd2f8..1c58ff6966 100644
--- a/src/test/regress/sql/date.sql
+++ b/src/test/regress/sql/date.sql
@@ -197,8 +197,8 @@ SELECT date '5874898-01-01';  -- out of range
 SELECT pg_input_is_valid('now', 'date');
 SELECT pg_input_is_valid('garbage', 'date');
 SELECT pg_input_is_valid('6874898-01-01', 'date');
-SELECT pg_input_error_message('garbage', 'date');
-SELECT pg_input_error_message('6874898-01-01', 'date');
+SELECT * FROM pg_input_error_info('garbage', 'date');
+SELECT * FROM pg_input_error_info('6874898-01-01', 'date');
 
 RESET datestyle;
 
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 1558bd9a33..a9a56f5277 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -77,12 +77,12 @@ create domain weirdfloat float8 check((1 / value) < 10);
 select pg_input_is_valid('1', 'positiveint');
 select pg_input_is_valid('junk', 'positiveint');
 select pg_input_is_valid('-1', 'positiveint');
-select pg_input_error_message('junk', 'positiveint');
-select pg_input_error_message('-1', 'positiveint');
-select pg_input_error_message('junk', 'weirdfloat');
-select pg_input_error_message('0.01', 'weirdfloat');
+select * from pg_input_error_info('junk', 'positiveint');
+select * from pg_input_error_info('-1', 'positiveint');
+select * from pg_input_error_info('junk', 'weirdfloat');
+select * from pg_input_error_info('0.01', 'weirdfloat');
 -- We currently can't trap errors raised in the CHECK expression itself
-select pg_input_error_message('0', 'weirdfloat');
+select * from pg_input_error_info('0', 'weirdfloat');
 
 drop domain positiveint;
 drop domain weirdfloat;
diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql
index c87656589b..93171379f2 100644
--- a/src/test/regress/sql/enum.sql
+++ b/src/test/regress/sql/enum.sql
@@ -18,8 +18,10 @@ SELECT 'mauve'::rainbow;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('red', 'rainbow');
 SELECT pg_input_is_valid('mauve', 'rainbow');
-SELECT pg_input_error_message('mauve', 'rainbow');
-SELECT pg_input_error_message(repeat('too_long', 32), 'rainbow');
+SELECT * FROM pg_input_error_info('mauve', 'rainbow');
+\x
+SELECT * FROM pg_input_error_info(repeat('too_long', 32), 'rainbow');
+\x
 
 --
 -- adding new values
diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4.sql
index 061477726b..8fb12368c3 100644
--- a/src/test/regress/sql/float4.sql
+++ b/src/test/regress/sql/float4.sql
@@ -40,7 +40,7 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
 SELECT pg_input_is_valid('34.5', 'float4');
 SELECT pg_input_is_valid('xyz', 'float4');
 SELECT pg_input_is_valid('1e400', 'float4');
-SELECT pg_input_error_message('1e400', 'float4');
+SELECT * FROM pg_input_error_info('1e400', 'float4');
 
 -- special inputs
 SELECT 'NaN'::float4;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index c276a5324c..8acef0fbab 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -38,7 +38,7 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123           5');
 SELECT pg_input_is_valid('34.5', 'float8');
 SELECT pg_input_is_valid('xyz', 'float8');
 SELECT pg_input_is_valid('1e4000', 'float8');
-SELECT pg_input_error_message('1e4000', 'float8');
+SELECT * FROM pg_input_error_info('1e4000', 'float8');
 
 -- special inputs
 SELECT 'NaN'::float8;
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 309234b76c..c3ea368da5 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -526,6 +526,6 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(1', 'circle');
-SELECT pg_input_error_message('1,', 'circle');
+SELECT * FROM pg_input_error_info('1,', 'circle');
 SELECT pg_input_is_valid('(1,2),-1', 'circle');
-SELECT pg_input_error_message('(1,2),-1', 'circle');
+SELECT * FROM pg_input_error_info('(1,2),-1', 'circle');
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index abfcd4242f..3910eac3bc 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -255,9 +255,9 @@ SELECT a FROM (VALUES
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1234', 'cidr');
-SELECT pg_input_error_message('1234', 'cidr');
+SELECT * FROM pg_input_error_info('1234', 'cidr');
 SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
-SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
+SELECT * FROM pg_input_error_info('192.168.198.200/24', 'cidr');
 
 SELECT pg_input_is_valid('1234', 'inet');
-SELECT pg_input_error_message('1234', 'inet');
+SELECT * FROM pg_input_error_info('1234', 'inet');
diff --git a/src/test/regress/sql/int2.sql b/src/test/regress/sql/int2.sql
index ce8ac97963..df1e46d4e2 100644
--- a/src/test/regress/sql/int2.sql
+++ b/src/test/regress/sql/int2.sql
@@ -21,12 +21,12 @@ SELECT * FROM INT2_TBL;
 SELECT pg_input_is_valid('34', 'int2');
 SELECT pg_input_is_valid('asdf', 'int2');
 SELECT pg_input_is_valid('50000', 'int2');
-SELECT pg_input_error_message('50000', 'int2');
+SELECT * FROM pg_input_error_info('50000', 'int2');
 
 -- While we're here, check int2vector as well
 SELECT pg_input_is_valid(' 1 3  5 ', 'int2vector');
-SELECT pg_input_error_message('1 asdf', 'int2vector');
-SELECT pg_input_error_message('50000', 'int2vector');
+SELECT * FROM pg_input_error_info('1 asdf', 'int2vector');
+SELECT * FROM pg_input_error_info('50000', 'int2vector');
 
 SELECT * FROM INT2_TBL AS f(a, b);
 
diff --git a/src/test/regress/sql/int4.sql b/src/test/regress/sql/int4.sql
index 146963edfb..e9d89e8111 100644
--- a/src/test/regress/sql/int4.sql
+++ b/src/test/regress/sql/int4.sql
@@ -21,7 +21,7 @@ SELECT * FROM INT4_TBL;
 SELECT pg_input_is_valid('34', 'int4');
 SELECT pg_input_is_valid('asdf', 'int4');
 SELECT pg_input_is_valid('1000000000000', 'int4');
-SELECT pg_input_error_message('1000000000000', 'int4');
+SELECT * FROM pg_input_error_info('1000000000000', 'int4');
 
 SELECT i.* FROM INT4_TBL i WHERE i.f1 <> int2 '0';
 
diff --git a/src/test/regress/sql/int8.sql b/src/test/regress/sql/int8.sql
index c85717c072..33f664dd02 100644
--- a/src/test/regress/sql/int8.sql
+++ b/src/test/regress/sql/int8.sql
@@ -20,7 +20,7 @@ SELECT * FROM INT8_TBL;
 SELECT pg_input_is_valid('34', 'int8');
 SELECT pg_input_is_valid('asdf', 'int8');
 SELECT pg_input_is_valid('10000000000000000000', 'int8');
-SELECT pg_input_error_message('10000000000000000000', 'int8');
+SELECT * FROM pg_input_error_info('10000000000000000000', 'int8');
 
 -- int8/int8 cmp
 SELECT * FROM INT8_TBL WHERE q2 = 4567890123456789;
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index af8e1ca0f4..56feda1a3d 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -36,8 +36,8 @@ INSERT INTO INTERVAL_TBL (f1) VALUES ('@ 30 eons ago');
 SELECT pg_input_is_valid('1.5 weeks', 'interval');
 SELECT pg_input_is_valid('garbage', 'interval');
 SELECT pg_input_is_valid('@ 30 eons ago', 'interval');
-SELECT pg_input_error_message('garbage', 'interval');
-SELECT pg_input_error_message('@ 30 eons ago', 'interval');
+SELECT * FROM pg_input_error_info('garbage', 'interval');
+SELECT * FROM pg_input_error_info('@ 30 eons ago', 'interval');
 
 -- test interval operators
 
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 21534ed959..ec57dfe707 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -84,7 +84,7 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'json');
 select pg_input_is_valid('{"a":true', 'json');
-select pg_input_error_message('{"a":true', 'json');
+select * from pg_input_error_info('{"a":true', 'json');
 
 --constructors
 -- array_to_json
diff --git a/src/test/regress/sql/json_encoding.sql b/src/test/regress/sql/json_encoding.sql
index f87b3bd4f3..aceb8dbc3c 100644
--- a/src/test/regress/sql/json_encoding.sql
+++ b/src/test/regress/sql/json_encoding.sql
@@ -79,4 +79,4 @@ SELECT jsonb '{ "a":  "null \\u0000 escape" }' ->> 'a' as not_an_escape;
 
 -- soft error for input-time failure
 
-select pg_input_error_message('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
+select * from pg_input_error_info('{ "a":  "\ud83d\ude04\ud83d\udc36" }', 'jsonb');
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 9f67f4c71d..e4b7cdf703 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -89,8 +89,8 @@ SELECT '{
 -- test non-error-throwing input
 select pg_input_is_valid('{"a":true}', 'jsonb');
 select pg_input_is_valid('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":true', 'jsonb');
-select pg_input_error_message('{"a":1e1000000}', 'jsonb');
+select * from pg_input_error_info('{"a":true', 'jsonb');
+select * from pg_input_error_info('{"a":1e1000000}', 'jsonb');
 
 -- make sure jsonb is passed through json generators without being escaped
 SELECT array_to_json(ARRAY [jsonb '{"a":1}', jsonb '{"b":[2,3]}']);
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 99d21d2af7..f2cd632729 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -192,9 +192,13 @@ select '1?(2>3)'::jsonpath;
 
 SELECT str as jsonpath,
        pg_input_is_valid(str,'jsonpath') as ok,
-       pg_input_error_message(str,'jsonpath') as errmsg
+       errinfo.sql_error_code,
+       errinfo.message,
+       errinfo.detail,
+       errinfo.hint
 FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
                   '$ ? (@ like_regex "pattern" flag "a")',
                   '@ + 1',
                   '00',
-                  '1a']) str;
+                  '1a']) str,
+     LATERAL pg_input_error_info(str, 'jsonpath') as errinfo;
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index f706a41184..1d0d3689c3 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -43,12 +43,12 @@ select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('{1, 1}', 'line');
-SELECT pg_input_error_message('{1, 1}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1}', 'line');
 SELECT pg_input_is_valid('{0, 0, 0}', 'line');
-SELECT pg_input_error_message('{0, 0, 0}', 'line');
+SELECT * FROM pg_input_error_info('{0, 0, 0}', 'line');
 SELECT pg_input_is_valid('{1, 1, a}', 'line');
-SELECT pg_input_error_message('{1, 1, a}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1, a}', 'line');
 SELECT pg_input_is_valid('{1, 1, 1e400}', 'line');
-SELECT pg_input_error_message('{1, 1, 1e400}', 'line');
+SELECT * FROM pg_input_error_info('{1, 1, 1e400}', 'line');
 SELECT pg_input_is_valid('(1, 1), (1, 1e400)', 'line');
-SELECT pg_input_error_message('(1, 1), (1, 1e400)', 'line');
+SELECT * FROM pg_input_error_info('(1, 1), (1, 1e400)', 'line');
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index 0fece162e0..d38a83eea6 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -25,4 +25,4 @@ select * from LSEG_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
-SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'lseg');
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index 211397c8f3..f61bdebe86 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -44,6 +44,6 @@ DROP TABLE macaddr_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:ZZ', 'macaddr');
 SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
-SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:', 'macaddr');
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
index b29f785b41..3c0cd70285 100644
--- a/src/test/regress/sql/macaddr8.sql
+++ b/src/test/regress/sql/macaddr8.sql
@@ -90,6 +90,6 @@ DROP TABLE macaddr8_data;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
 SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
-SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
+SELECT * FROM pg_input_error_info('08:00:2b:01:02:03:04:', 'macaddr8');
diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql
index cd9a089e01..81c92dd960 100644
--- a/src/test/regress/sql/money.sql
+++ b/src/test/regress/sql/money.sql
@@ -90,9 +90,9 @@ SELECT '($123,456.78)'::money;
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('\x0001', 'money');
-SELECT pg_input_error_message('\x0001', 'money');
+SELECT * FROM pg_input_error_info('\x0001', 'money');
 SELECT pg_input_is_valid('192233720368547758.07', 'money');
-SELECT pg_input_error_message('192233720368547758.07', 'money');
+SELECT * FROM pg_input_error_info('192233720368547758.07', 'money');
 
 -- documented minimums and maximums
 SELECT '-92233720368547758.08'::money;
diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql
index fc369a550c..fefb4b4d42 100644
--- a/src/test/regress/sql/multirangetypes.sql
+++ b/src/test/regress/sql/multirangetypes.sql
@@ -61,9 +61,9 @@ select '{(a,a)}'::textmultirange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('{[1,2], [4,5]}', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,5]', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,5]', 'int4multirange');
+select * from pg_input_error_info('{[1,2], [4,5]', 'int4multirange');
 select pg_input_is_valid('{[1,2], [4,zed]}', 'int4multirange');
-select pg_input_error_message('{[1,2], [4,zed]}', 'int4multirange');
+select * from pg_input_error_info('{[1,2], [4,zed]}', 'int4multirange');
 
 --
 -- test the constructor
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 2db7656e84..6e9e6145d0 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1086,11 +1086,11 @@ SELECT * FROM num_input_test;
 SELECT pg_input_is_valid('34.5', 'numeric');
 SELECT pg_input_is_valid('34xyz', 'numeric');
 SELECT pg_input_is_valid('1e400000', 'numeric');
-SELECT pg_input_error_message('1e400000', 'numeric');
+SELECT * FROM pg_input_error_info('1e400000', 'numeric');
 SELECT pg_input_is_valid('1234.567', 'numeric(8,4)');
 SELECT pg_input_is_valid('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('1234.567', 'numeric(7,4)');
-SELECT pg_input_error_message('0x1234.567', 'numeric');
+SELECT * FROM pg_input_error_info('1234.567', 'numeric(7,4)');
+SELECT * FROM pg_input_error_info('0x1234.567', 'numeric');
 
 --
 -- Test precision and scale typemods
diff --git a/src/test/regress/sql/oid.sql b/src/test/regress/sql/oid.sql
index 39937c2f1d..a96b2aa1e3 100644
--- a/src/test/regress/sql/oid.sql
+++ b/src/test/regress/sql/oid.sql
@@ -31,16 +31,16 @@ SELECT * FROM OID_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('1234', 'oid');
 SELECT pg_input_is_valid('01XYZ', 'oid');
-SELECT pg_input_error_message('01XYZ', 'oid');
+SELECT * FROM pg_input_error_info('01XYZ', 'oid');
 SELECT pg_input_is_valid('9999999999', 'oid');
-SELECT pg_input_error_message('9999999999', 'oid');
+SELECT * FROM pg_input_error_info('9999999999', 'oid');
 
 -- While we're here, check oidvector as well
 SELECT pg_input_is_valid(' 1 2  4 ', 'oidvector');
 SELECT pg_input_is_valid('01 01XYZ', 'oidvector');
-SELECT pg_input_error_message('01 01XYZ', 'oidvector');
+SELECT * FROM pg_input_error_info('01 01XYZ', 'oidvector');
 SELECT pg_input_is_valid('01 9999999999', 'oidvector');
-SELECT pg_input_error_message('01 9999999999', 'oidvector');
+SELECT * FROM pg_input_error_info('01 9999999999', 'oidvector');
 
 SELECT o.* FROM OID_TBL o WHERE o.f1 = 1234;
 
diff --git a/src/test/regress/sql/path.sql b/src/test/regress/sql/path.sql
index 42c90afe53..8422ba961c 100644
--- a/src/test/regress/sql/path.sql
+++ b/src/test/regress/sql/path.sql
@@ -45,6 +45,6 @@ SELECT popen(f1) AS open_path FROM PATH_TBL;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('[(1,2),(3)]', 'path');
-SELECT pg_input_error_message('[(1,2),(3)]', 'path');
+SELECT * FROM pg_input_error_info('[(1,2),(3)]', 'path');
 SELECT pg_input_is_valid('[(1,2,6),(3,4,6)]', 'path');
-SELECT pg_input_error_message('[(1,2,6),(3,4,6)]', 'path');
+SELECT * FROM pg_input_error_info('[(1,2,6),(3,4,6)]', 'path');
diff --git a/src/test/regress/sql/pg_lsn.sql b/src/test/regress/sql/pg_lsn.sql
index 3d57d66e0c..98c869df15 100644
--- a/src/test/regress/sql/pg_lsn.sql
+++ b/src/test/regress/sql/pg_lsn.sql
@@ -17,7 +17,7 @@ INSERT INTO PG_LSN_TBL VALUES ('/ABCD');
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('16AE7F7', 'pg_lsn');
-SELECT pg_input_error_message('16AE7F7', 'pg_lsn');
+SELECT * FROM pg_input_error_info('16AE7F7', 'pg_lsn');
 
 -- Min/Max aggregation
 SELECT MIN(f1), MAX(f1) FROM PG_LSN_TBL;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 7bd1ebe2b5..b1a29eb229 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -99,4 +99,4 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('1,y', 'point');
-SELECT pg_input_error_message('1,y', 'point');
+SELECT * FROM pg_input_error_info('1,y', 'point');
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index da644e34e3..9f6c5d5ea1 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -143,6 +143,6 @@ RESET enable_bitmapscan;
 
 -- test non-error-throwing API for some core types
 SELECT pg_input_is_valid('(2.0,0.8,0.1)', 'polygon');
-SELECT pg_input_error_message('(2.0,0.8,0.1)', 'polygon');
+SELECT * FROM pg_input_error_info('(2.0,0.8,0.1)', 'polygon');
 SELECT pg_input_is_valid('(2.0,xyz)', 'polygon');
-SELECT pg_input_error_message('(2.0,xyz)', 'polygon');
+SELECT * FROM pg_input_error_info('(2.0,xyz)', 'polygon');
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 0bcea77ff4..134809e8cc 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -1433,11 +1433,11 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
 -- Test non-throwing aclitem I/O
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=r/regress_no_such_user', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=r/regress_no_such_user', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=r/regress_no_such_user', 'aclitem');
 SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
-SELECT pg_input_error_message('regress_priv_user1=rY', 'aclitem');
+SELECT * FROM pg_input_error_info('regress_priv_user1=rY', 'aclitem');
 
 --
 -- Testing blanket default grants is very hazardous since it might change
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index 4e6a0912de..c23be928c3 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -43,15 +43,15 @@ select '(a,a)'::textrange;
 -- Also try it with non-error-throwing API
 select pg_input_is_valid('(1,4)', 'int4range');
 select pg_input_is_valid('(1,4', 'int4range');
-select pg_input_error_message('(1,4', 'int4range');
+select * from pg_input_error_info('(1,4', 'int4range');
 select pg_input_is_valid('(4,1)', 'int4range');
-select pg_input_error_message('(4,1)', 'int4range');
+select * from pg_input_error_info('(4,1)', 'int4range');
 select pg_input_is_valid('(4,zed)', 'int4range');
-select pg_input_error_message('(4,zed)', 'int4range');
+select * from pg_input_error_info('(4,zed)', 'int4range');
 select pg_input_is_valid('[1,2147483647]', 'int4range');
-select pg_input_error_message('[1,2147483647]', 'int4range');
+select * from pg_input_error_info('[1,2147483647]', 'int4range');
 select pg_input_is_valid('[2000-01-01,5874897-12-31]', 'daterange');
-select pg_input_error_message('[2000-01-01,5874897-12-31]', 'daterange');
+select * from pg_input_error_info('[2000-01-01,5874897-12-31]', 'daterange');
 
 --
 -- create some test data and test the operators
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index 2cb8c9a253..de2aa881a8 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -125,23 +125,23 @@ SELECT to_regnamespace('foo.bar');
 
 -- Test soft-error API
 
-SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
+SELECT * FROM pg_input_error_info('ng_catalog.pg_class', 'regclass');
 SELECT pg_input_is_valid('ng_catalog."POSIX"', 'regcollation');
-SELECT pg_input_error_message('no_such_config', 'regconfig');
-SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
-SELECT pg_input_error_message('Nonexistent', 'regnamespace');
-SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
-SELECT pg_input_error_message('-', 'regoper');
-SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
-SELECT pg_input_error_message('-', 'regoperator');
-SELECT pg_input_error_message('ng_catalog.now', 'regproc');
-SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
-SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
-SELECT pg_input_error_message('regress_regrole_test', 'regrole');
-SELECT pg_input_error_message('no_such_type', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_config', 'regconfig');
+SELECT * FROM pg_input_error_info('no_such_dictionary', 'regdictionary');
+SELECT * FROM pg_input_error_info('Nonexistent', 'regnamespace');
+SELECT * FROM pg_input_error_info('ng_catalog.||/', 'regoper');
+SELECT * FROM pg_input_error_info('-', 'regoper');
+SELECT * FROM pg_input_error_info('ng_catalog.+(int4,int4)', 'regoperator');
+SELECT * FROM pg_input_error_info('-', 'regoperator');
+SELECT * FROM pg_input_error_info('ng_catalog.now', 'regproc');
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric)', 'regprocedure');
+SELECT * FROM pg_input_error_info('ng_catalog.abs(numeric', 'regprocedure');
+SELECT * FROM pg_input_error_info('regress_regrole_test', 'regrole');
+SELECT * FROM pg_input_error_info('no_such_type', 'regtype');
 
 -- Some cases that should be soft errors, but are not yet
-SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
-SELECT pg_input_error_message('numeric(1,2,3)', 'regtype');  -- bogus typmod
-SELECT pg_input_error_message('way.too.many.names', 'regtype');
-SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
+SELECT * FROM pg_input_error_info('incorrect type name syntax', 'regtype');
+SELECT * FROM pg_input_error_info('numeric(1,2,3)', 'regtype');  -- bogus typmod
+SELECT * FROM pg_input_error_info('way.too.many.names', 'regtype');
+SELECT * FROM pg_input_error_info('no_such_catalog.schema.name', 'regtype');
diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql
index 0844e7488d..1ec2824516 100644
--- a/src/test/regress/sql/rowtypes.sql
+++ b/src/test/regress/sql/rowtypes.sql
@@ -35,8 +35,8 @@ select '(Joe,Blow) /'::fullname;  -- bad
 SELECT pg_input_is_valid('(1,2)', 'complex');
 SELECT pg_input_is_valid('(1,2', 'complex');
 SELECT pg_input_is_valid('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,zed)', 'complex');
-SELECT pg_input_error_message('(1,1e400)', 'complex');
+SELECT * FROM pg_input_error_info('(1,zed)', 'complex');
+SELECT * FROM pg_input_error_info('(1,1e400)', 'complex');
 
 create temp table quadtable(f1 int, q quad);
 
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 932f71cbca..097dcdf69e 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -87,9 +87,9 @@ SELECT E'De\\123dBeEf'::bytea;
 
 -- Test non-error-throwing API too
 SELECT pg_input_is_valid(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeE', 'bytea');
-SELECT pg_input_error_message(E'\\xDeAdBeEx', 'bytea');
-SELECT pg_input_error_message(E'foo\\99bar', 'bytea');
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeE', 'bytea');
+SELECT * FROM pg_input_error_info(E'\\xDeAdBeEx', 'bytea');
+SELECT * FROM pg_input_error_info(E'foo\\99bar', 'bytea');
 
 --
 -- test conversions between various string types
diff --git a/src/test/regress/sql/tid.sql b/src/test/regress/sql/tid.sql
index 8196194c04..2602e20eb5 100644
--- a/src/test/regress/sql/tid.sql
+++ b/src/test/regress/sql/tid.sql
@@ -11,9 +11,9 @@ SELECT '(1,65536)'::tid;  -- error
 
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('(0)', 'tid');
-SELECT pg_input_error_message('(0)', 'tid');
+SELECT * FROM pg_input_error_info('(0)', 'tid');
 SELECT pg_input_is_valid('(0,-1)', 'tid');
-SELECT pg_input_error_message('(0,-1)', 'tid');
+SELECT * FROM pg_input_error_info('(0,-1)', 'tid');
 
 
 -- tests for functions related to TID handling
diff --git a/src/test/regress/sql/time.sql b/src/test/regress/sql/time.sql
index b439cd6b41..eb375a36e9 100644
--- a/src/test/regress/sql/time.sql
+++ b/src/test/regress/sql/time.sql
@@ -44,8 +44,8 @@ SELECT '25:00:00'::time;  -- not allowed
 SELECT pg_input_is_valid('12:00:00', 'time');
 SELECT pg_input_is_valid('25:00:00', 'time');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'time');
-SELECT pg_input_error_message('25:00:00', 'time');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'time');
+SELECT * FROM pg_input_error_info('25:00:00', 'time');
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'time');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index 2d5f01ab86..b9bcce9cfe 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -100,8 +100,8 @@ INSERT INTO TIMESTAMP_TBL VALUES ('19970710 173201 America/Does_not_exist');
 SELECT pg_input_is_valid('now', 'timestamp');
 SELECT pg_input_is_valid('garbage', 'timestamp');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
-SELECT pg_input_error_message('garbage', 'timestamp');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
+SELECT * FROM pg_input_error_info('garbage', 'timestamp');
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamp');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMP_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index 6d10937d86..ae9ee4b56a 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -113,8 +113,8 @@ SELECT '205000-01-10 17:32:01 Europe/Helsinki'::timestamptz; -- non-DST
 SELECT pg_input_is_valid('now', 'timestamptz');
 SELECT pg_input_is_valid('garbage', 'timestamptz');
 SELECT pg_input_is_valid('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
-SELECT pg_input_error_message('garbage', 'timestamptz');
-SELECT pg_input_error_message('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
+SELECT * FROM pg_input_error_info('garbage', 'timestamptz');
+SELECT * FROM pg_input_error_info('2001-01-01 00:00 Nehwon/Lankhmar', 'timestamptz');
 
 -- Check date conversion and date arithmetic
 INSERT INTO TIMESTAMPTZ_TBL VALUES ('1997-06-10 18:32:01 PDT');
diff --git a/src/test/regress/sql/timetz.sql b/src/test/regress/sql/timetz.sql
index b62aa3fe05..93c7bb1428 100644
--- a/src/test/regress/sql/timetz.sql
+++ b/src/test/regress/sql/timetz.sql
@@ -49,8 +49,8 @@ SELECT '25:00:00 PDT'::timetz;  -- not allowed
 SELECT pg_input_is_valid('12:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('25:00:00 PDT', 'timetz');
 SELECT pg_input_is_valid('15:36:39 America/New_York', 'timetz');
-SELECT pg_input_error_message('25:00:00 PDT', 'timetz');
-SELECT pg_input_error_message('15:36:39 America/New_York', 'timetz');
+SELECT * FROM pg_input_error_info('25:00:00 PDT', 'timetz');
+SELECT * FROM pg_input_error_info('15:36:39 America/New_York', 'timetz');
 
 --
 -- TIME simple math
diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql
index b73dd1cb07..dfb7a1466e 100644
--- a/src/test/regress/sql/tstypes.sql
+++ b/src/test/regress/sql/tstypes.sql
@@ -22,7 +22,7 @@ SELECT $$'' '1' '2'$$::tsvector;  -- error, empty lexeme is not allowed
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsvector');
 SELECT pg_input_is_valid($$''$$, 'tsvector');
-SELECT pg_input_error_message($$''$$, 'tsvector');
+SELECT * FROM pg_input_error_info($$''$$, 'tsvector');
 
 --Base tsquery test
 SELECT '1'::tsquery;
@@ -76,8 +76,8 @@ SELECT '!!a & !!b'::tsquery;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('foo', 'tsquery');
 SELECT pg_input_is_valid('foo!', 'tsquery');
-SELECT pg_input_error_message('foo!', 'tsquery');
-SELECT pg_input_error_message('a <100000> b', 'tsquery');
+SELECT * FROM pg_input_error_info('foo!', 'tsquery');
+SELECT * FROM pg_input_error_info('a <100000> b', 'tsquery');
 
 --comparisons
 SELECT 'a' < 'b & c'::tsquery as "true";
diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql
index 37d954eda1..9a8f437c7d 100644
--- a/src/test/regress/sql/uuid.sql
+++ b/src/test/regress/sql/uuid.sql
@@ -25,7 +25,7 @@ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
 
 -- test non-error-throwing API
 SELECT pg_input_is_valid('11', 'uuid');
-SELECT pg_input_error_message('11', 'uuid');
+SELECT * FROM pg_input_error_info('11', 'uuid');
 
 --inserting three input formats
 INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
diff --git a/src/test/regress/sql/varchar.sql b/src/test/regress/sql/varchar.sql
index df16da37a7..c8aaf93e8a 100644
--- a/src/test/regress/sql/varchar.sql
+++ b/src/test/regress/sql/varchar.sql
@@ -70,4 +70,4 @@ SELECT * FROM VARCHAR_TBL;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('abcd  ', 'varchar(4)');
 SELECT pg_input_is_valid('abcde', 'varchar(4)');
-SELECT pg_input_error_message('abcde', 'varchar(4)');
+SELECT * FROM pg_input_error_info('abcde', 'varchar(4)');
diff --git a/src/test/regress/sql/xid.sql b/src/test/regress/sql/xid.sql
index b6996588ef..9f716b3653 100644
--- a/src/test/regress/sql/xid.sql
+++ b/src/test/regress/sql/xid.sql
@@ -19,10 +19,10 @@ select 'asdf'::xid8;
 -- Also try it with non-error-throwing API
 SELECT pg_input_is_valid('42', 'xid');
 SELECT pg_input_is_valid('asdf', 'xid');
-SELECT pg_input_error_message('0xffffffffff', 'xid');
+SELECT * FROM pg_input_error_info('0xffffffffff', 'xid');
 SELECT pg_input_is_valid('42', 'xid8');
 SELECT pg_input_is_valid('asdf', 'xid8');
-SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
+SELECT * FROM pg_input_error_info('0xffffffffffffffffffff', 'xid8');
 
 -- equality
 select '1'::xid = '1'::xid;
@@ -79,9 +79,9 @@ select '12:16:14,13'::pg_snapshot;
 -- also try it with non-error-throwing API
 select pg_input_is_valid('12:13:', 'pg_snapshot');
 select pg_input_is_valid('31:12:', 'pg_snapshot');
-select pg_input_error_message('31:12:', 'pg_snapshot');
+select * from pg_input_error_info('31:12:', 'pg_snapshot');
 select pg_input_is_valid('12:16:14,13', 'pg_snapshot');
-select pg_input_error_message('12:16:14,13', 'pg_snapshot');
+select * from pg_input_error_info('12:16:14,13', 'pg_snapshot');
 
 create temp table snapshot_test (
 	nr	integer,
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ddff459297..24e40d2653 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -12,9 +12,9 @@ SELECT * FROM xmltest;
 -- test non-throwing API, too
 SELECT pg_input_is_valid('<value>one</value>', 'xml');
 SELECT pg_input_is_valid('<value>one</', 'xml');
-SELECT pg_input_error_message('<value>one</', 'xml');
+SELECT message FROM pg_input_error_info('<value>one</', 'xml');
 SELECT pg_input_is_valid('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
-SELECT pg_input_error_message('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
+SELECT message FROM pg_input_error_info('<?xml version="1.0" standalone="y"?><foo/>', 'xml');
 
 
 SELECT xmlcomment('test');
-- 
2.25.1

#16Michael Paquier
michael@paquier.xyz
In reply to: Nathan Bossart (#15)
Re: verbose mode for pg_input_error_message?

On Mon, Feb 27, 2023 at 11:25:01AM -0800, Nathan Bossart wrote:

I found a couple of more small changes required to make cfbot happy.
Otherwise, it looks good to me.

Thanks, I have confirmed the spots the CI was complaining about, so
applied. There was an extra place that was not right in xml_2.out as
reported by prion, parula and snakefly because of a bad copy-paste, so
fixed as well.
--
Michael

#17Nathan Bossart
nathandbossart@gmail.com
In reply to: Michael Paquier (#16)
Re: verbose mode for pg_input_error_message?

On Tue, Feb 28, 2023 at 09:01:48AM +0900, Michael Paquier wrote:

On Mon, Feb 27, 2023 at 11:25:01AM -0800, Nathan Bossart wrote:

I found a couple of more small changes required to make cfbot happy.
Otherwise, it looks good to me.

Thanks, I have confirmed the spots the CI was complaining about, so
applied. There was an extra place that was not right in xml_2.out as
reported by prion, parula and snakefly because of a bad copy-paste, so
fixed as well.

Thanks!

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com