From 45d93d558218ddb303fe1b57297c48855dde8cf0 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 24 Aug 2025 14:07:28 -0400
Subject: [PATCH v4 3/4] Improve the messages for operator-not-found, too.

Extend the same return-a-bitmask approach to OpernameGetCandidates.
The issues around argument names don't apply to operator syntax,
but it still seems worth distinguishing between "there is no
operator of that name" and "we couldn't match the argument types".

Also follow the previous patch's improvement of style by
separating errdetail from errhint.

Reported-by: Dominique Devienne <ddevienne@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1756041.1754616558@sss.pgh.pa.us
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 +-
 src/backend/catalog/namespace.c               | 24 ++++++-
 src/backend/parser/parse_oper.c               | 65 +++++++++++++++----
 src/backend/utils/adt/regproc.c               |  6 +-
 src/include/catalog/namespace.h               |  3 +-
 src/test/regress/expected/alter_table.out     |  3 +-
 .../regress/expected/create_function_sql.out  |  3 +-
 src/test/regress/expected/create_view.out     |  3 +-
 src/test/regress/expected/domain.out          |  3 +-
 src/test/regress/expected/expressions.out     |  3 +-
 src/test/regress/expected/geometry.out        |  3 +-
 src/test/regress/expected/horology.out        |  3 +-
 src/test/regress/expected/plpgsql.out         |  3 +-
 src/test/regress/expected/polymorphism.out    |  3 +-
 src/test/regress/expected/subselect.out       |  3 +-
 src/test/regress/expected/text.out            |  3 +-
 src/test/regress/expected/timetz.out          |  3 +-
 src/test/regress/expected/with.out            |  3 +-
 src/test/regress/expected/xid.out             | 12 ++--
 19 files changed, 120 insertions(+), 35 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index d3323b04676..35c619226a6 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -4621,11 +4621,13 @@ SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
 -- with that remote type
 SELECT * FROM ft1 WHERE c8 LIKE 'foo' LIMIT 1; -- ERROR
 ERROR:  operator does not exist: public.user_enum ~~ unknown
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 CONTEXT:  remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
 SELECT * FROM ft1 WHERE c8::text LIKE 'foo' LIMIT 1; -- ERROR; cast not pushed down
 ERROR:  operator does not exist: public.user_enum ~~ unknown
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 CONTEXT:  remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
 -- ===================================================================
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index c54cbbd7a35..0411977a9ed 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1931,9 +1931,20 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  *
  * The returned items always have two args[] entries --- the first will be
  * InvalidOid for a prefix oprkind.  nargs is always 2, too.
+ *
+ * We return an empty list (NULL) if no suitable matches can be found.  If the
+ * operator name was schema-qualified with a schema that does not exist, then
+ * we return an empty list if missing_schema_ok is true and otherwise throw an
+ * error.  (missing_schema_ok does not affect the behavior otherwise.)
+ *
+ * The output argument *fgc_flags is filled with a bitmask indicating how
+ * far we were able to match the supplied information.  This is not of much
+ * interest if any candidates were found, but if not, it can help callers
+ * produce an on-point error message.
  */
 FuncCandidateList
-OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
+OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok,
+					  int *fgc_flags)
 {
 	FuncCandidateList resultList = NULL;
 	char	   *resultSpace = NULL;
@@ -1944,15 +1955,20 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
 	CatCList   *catlist;
 	int			i;
 
+	/* initialize output fgc_flags to empty */
+	*fgc_flags = 0;
+
 	/* deconstruct the name list */
 	DeconstructQualifiedName(names, &schemaname, &opername);
 
 	if (schemaname)
 	{
 		/* use exact schema given */
+		*fgc_flags |= FGC_SCHEMA_GIVEN; /* report that a schema is given */
 		namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok);
-		if (missing_schema_ok && !OidIsValid(namespaceId))
+		if (!OidIsValid(namespaceId))
 			return NULL;
+		*fgc_flags |= FGC_SCHEMA_EXISTS;	/* report that the schema exists */
 	}
 	else
 	{
@@ -1990,6 +2006,8 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
 		if (oprkind && operform->oprkind != oprkind)
 			continue;
 
+		*fgc_flags |= FGC_NAME_EXISTS;	/* the name is present in pg_operator */
+
 		if (OidIsValid(namespaceId))
 		{
 			/* Consider only opers in specified namespace */
@@ -2063,6 +2081,8 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
 			}
 		}
 
+		*fgc_flags |= FGC_NAME_VISIBLE; /* operator is in the right schema */
+
 		/*
 		 * Okay to add it to result list
 		 */
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 0c4337563cf..fafdf0a80a3 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -72,7 +72,8 @@ static FuncDetailCode oper_select_candidate(int nargs,
 											Oid *operOid);
 static void op_error(ParseState *pstate, List *op,
 					 Oid arg1, Oid arg2,
-					 FuncDetailCode fdresult, int location);
+					 FuncDetailCode fdresult, int fgc_flags, int location);
+static int	oper_lookup_failure_details(int fgc_flags, bool is_unary_op);
 static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
 								List *opname, Oid ltypeId, Oid rtypeId,
 								int location);
@@ -373,6 +374,7 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 	Oid			operOid;
 	OprCacheKey key;
 	bool		key_ok;
+	int			fgc_flags = 0;
 	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
 	HeapTuple	tup = NULL;
 
@@ -404,7 +406,7 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 		FuncCandidateList clist;
 
 		/* Get binary operators of given name */
-		clist = OpernameGetCandidates(opname, 'b', false);
+		clist = OpernameGetCandidates(opname, 'b', false, &fgc_flags);
 
 		/* No operators found? Then fail... */
 		if (clist != NULL)
@@ -434,7 +436,8 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 			make_oper_cache_entry(&key, operOid);
 	}
 	else if (!noError)
-		op_error(pstate, opname, ltypeId, rtypeId, fdresult, location);
+		op_error(pstate, opname, ltypeId, rtypeId,
+				 fdresult, fgc_flags, location);
 
 	return (Operator) tup;
 }
@@ -520,6 +523,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 	Oid			operOid;
 	OprCacheKey key;
 	bool		key_ok;
+	int			fgc_flags = 0;
 	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
 	HeapTuple	tup = NULL;
 
@@ -551,7 +555,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 		FuncCandidateList clist;
 
 		/* Get prefix operators of given name */
-		clist = OpernameGetCandidates(op, 'l', false);
+		clist = OpernameGetCandidates(op, 'l', false, &fgc_flags);
 
 		/* No operators found? Then fail... */
 		if (clist != NULL)
@@ -585,7 +589,8 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 			make_oper_cache_entry(&key, operOid);
 	}
 	else if (!noError)
-		op_error(pstate, op, InvalidOid, arg, fdresult, location);
+		op_error(pstate, op, InvalidOid, arg,
+				 fdresult, fgc_flags, location);
 
 	return (Operator) tup;
 }
@@ -621,7 +626,7 @@ op_signature_string(List *op, Oid arg1, Oid arg2)
 static void
 op_error(ParseState *pstate, List *op,
 		 Oid arg1, Oid arg2,
-		 FuncDetailCode fdresult, int location)
+		 FuncDetailCode fdresult, int fgc_flags, int location)
 {
 	if (fdresult == FUNCDETAIL_MULTIPLE)
 		ereport(ERROR,
@@ -636,14 +641,52 @@ op_error(ParseState *pstate, List *op,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s",
 						op_signature_string(op, arg1, arg2)),
-				 (!arg1 || !arg2) ?
-				 errhint("No operator matches the given name and argument type. "
-						 "You might need to add an explicit type cast.") :
-				 errhint("No operator matches the given name and argument types. "
-						 "You might need to add explicit type casts."),
+				 oper_lookup_failure_details(fgc_flags, (!arg1 || !arg2)),
 				 parser_errposition(pstate, location)));
 }
 
+/*
+ * Interpret the fgc_flags and issue a suitable detail or hint message.
+ */
+static int
+oper_lookup_failure_details(int fgc_flags, bool is_unary_op)
+{
+	/*
+	 * If not FGC_NAME_VISIBLE, we shouldn't raise the question of whether the
+	 * arguments are wrong.  If the operator name was not schema-qualified,
+	 * it's helpful to distinguish between doesn't-exist-anywhere and
+	 * not-in-search-path; but if it was, there's really nothing to add to the
+	 * basic "operator does not exist" message.
+	 *
+	 * Note: we passed missing_ok = false to OpernameGetCandidates, so there's
+	 * no need to consider FGC_SCHEMA_EXISTS here: we'd have already thrown an
+	 * error if an explicitly-given schema doesn't exist.
+	 */
+	if (!(fgc_flags & FGC_NAME_VISIBLE))
+	{
+		if (fgc_flags & FGC_SCHEMA_GIVEN)
+			return 0;			/* schema-qualified name */
+		else if (!(fgc_flags & FGC_NAME_EXISTS))
+			return errdetail("There is no operator of that name.");
+		else
+			return errdetail("An operator of that name exists, but it is not in the search_path.");
+	}
+
+	/*
+	 * Otherwise, the problem must be incorrect argument type(s).
+	 */
+	if (is_unary_op)
+	{
+		(void) errdetail("No operator of that name accepts the given argument type.");
+		return errhint("You might need to add an explicit type cast.");
+	}
+	else
+	{
+		(void) errdetail("No operator of that name accepts the given argument types.");
+		return errhint("You might need to add explicit type casts.");
+	}
+}
+
 /*
  * make_op()
  *		Operator expression construction.
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 0c5dec025d7..2709024a4ad 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -488,6 +488,7 @@ regoperin(PG_FUNCTION_ARGS)
 	Oid			result;
 	List	   *names;
 	FuncCandidateList clist;
+	int			fgc_flags;
 
 	/* Handle "0" or numeric OID */
 	if (parseNumericOid(opr_name_or_oid, &result, escontext))
@@ -507,7 +508,7 @@ regoperin(PG_FUNCTION_ARGS)
 	if (names == NIL)
 		PG_RETURN_NULL();
 
-	clist = OpernameGetCandidates(names, '\0', true);
+	clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
 
 	if (clist == NULL)
 		ereturn(escontext, (Datum) 0,
@@ -577,13 +578,14 @@ regoperout(PG_FUNCTION_ARGS)
 		else
 		{
 			FuncCandidateList clist;
+			int			fgc_flags;
 
 			/*
 			 * Would this oper be found (uniquely!) by regoperin? If not,
 			 * qualify it.
 			 */
 			clist = OpernameGetCandidates(list_make1(makeString(oprname)),
-										  '\0', false);
+										  '\0', false, &fgc_flags);
 			if (clist != NULL && clist->next == NULL &&
 				clist->oid == oprid)
 				result = pstrdup(oprname);
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 977c015f3aa..f1423f28c32 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -126,7 +126,8 @@ extern bool FunctionIsVisible(Oid funcid);
 
 extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind,
-											   bool missing_schema_ok);
+											   bool missing_schema_ok,
+											   int *fgc_flags);
 extern bool OperatorIsVisible(Oid oprid);
 
 extern Oid	OpclassnameGetOpcid(Oid amid, const char *opcname);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index b33e06a0d3d..a08f115b0e5 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -2041,7 +2041,8 @@ alter table anothertab alter column atcol1 drop default;
 alter table anothertab alter column atcol1 type boolean
         using case when atcol1 % 2 = 0 then true else false end; -- fails
 ERROR:  operator does not exist: boolean <= integer
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 alter table anothertab drop constraint anothertab_chk;
 alter table anothertab drop constraint anothertab_chk; -- fails
 ERROR:  constraint "anothertab_chk" of relation "anothertab" does not exist
diff --git a/src/test/regress/expected/create_function_sql.out b/src/test/regress/expected/create_function_sql.out
index da112608d66..73c6730d459 100644
--- a/src/test/regress/expected/create_function_sql.out
+++ b/src/test/regress/expected/create_function_sql.out
@@ -304,7 +304,8 @@ CREATE FUNCTION functest_S_xx(x date) RETURNS boolean
 ERROR:  operator does not exist: date > integer
 LINE 3:     RETURN x > 1;
                      ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 -- tricky parsing
 CREATE FUNCTION functest_S_15(x int) RETURNS boolean
 LANGUAGE SQL
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index f551624afb3..49dd13c345c 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1924,7 +1924,8 @@ select 'foo'::text = any((select array['abc','def','foo']::text[]));  -- fail
 ERROR:  operator does not exist: text = text[]
 LINE 1: select 'foo'::text = any((select array['abc','def','foo']::t...
                            ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
  ?column? 
 ----------
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index b5ea707df31..62a48a523a2 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -415,7 +415,8 @@ select row(0,1)::dcomptype;  -- fail
 ERROR:  value for domain dcomptype violates check constraint "c1"
 alter type comptype alter attribute r type varchar;  -- fail
 ERROR:  operator does not exist: character varying > double precision
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 alter type comptype alter attribute r type bigint;
 alter type comptype drop attribute r;  -- fail
 ERROR:  cannot drop column r of composite type comptype because other objects depend on it
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 21c54fc1989..9a3c97b15a3 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -218,7 +218,8 @@ select '(0,0)'::point in ('(0,0,0,0)'::box, point(0,0));
 ERROR:  operator does not exist: point = box
 LINE 1: select '(0,0)'::point in ('(0,0,0,0)'::box, point(0,0));
                               ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 --
 -- Tests for ScalarArrayOpExpr with a hashfn
 --
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 8be694f46be..1d168b21cbc 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -1777,7 +1777,8 @@ SELECT p.f1, l.s, l.s # p.f1 AS intersection
 ERROR:  operator does not exist: lseg # point
 LINE 1: SELECT p.f1, l.s, l.s # p.f1 AS intersection
                               ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 -- Length
 SELECT s, @-@ s FROM LSEG_TBL;
                s               |   ?column?    
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 5ae93d8e8a5..32cf62b6741 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -605,7 +605,8 @@ SELECT date '1991-02-03' - time with time zone '04:05:06 UTC' AS "Subtract Time
 ERROR:  operator does not exist: date - time with time zone
 LINE 1: SELECT date '1991-02-03' - time with time zone '04:05:06 UTC...
                                  ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 --
 -- timestamp, interval arithmetic
 --
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index d320b4d43de..474be478ce8 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1763,7 +1763,8 @@ select f1(point(3,4));  -- fail for lack of + operator
 ERROR:  operator does not exist: point + integer
 LINE 1: x + 1
           ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 QUERY:  x + 1
 CONTEXT:  PL/pgSQL function f1(anyelement) line 3 at RETURN
 drop function f1(x anyelement);
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index 74bdb1ffdca..dd38d950d81 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -15,7 +15,8 @@ select polyf(point(3,4));  -- fail for lack of + operator
 ERROR:  operator does not exist: point + integer
 LINE 2:   select x + 1
                    ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 QUERY:  
   select x + 1
 
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index 0563d0cd5a1..637b55f1414 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -1156,7 +1156,8 @@ select * from int8_tbl where q1 in (select c1 from inner_text);
 ERROR:  operator does not exist: bigint = text
 LINE 1: select * from int8_tbl where q1 in (select c1 from inner_tex...
                                         ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 begin;
 -- make an operator to allow it to succeed
 create function bogus_int8_text_eq(int8, text) returns boolean
diff --git a/src/test/regress/expected/text.out b/src/test/regress/expected/text.out
index ced71e903c6..3f9982388ba 100644
--- a/src/test/regress/expected/text.out
+++ b/src/test/regress/expected/text.out
@@ -49,7 +49,8 @@ select 3 || 4.0;
 ERROR:  operator does not exist: integer || numeric
 LINE 1: select 3 || 4.0;
                  ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 /*
  * various string functions
  */
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index cbab6cfe5d7..324b1a740e8 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -174,7 +174,8 @@ SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TIMETZ_TBL;
 ERROR:  operator does not exist: time with time zone + time with time zone
 LINE 1: SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TI...
                   ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 --
 -- test EXTRACT
 --
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 26c88505140..f015e997276 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -175,7 +175,8 @@ SELECT n, pg_typeof(n) FROM t;
 ERROR:  operator does not exist: text + integer
 LINE 4:     SELECT n+1 FROM t WHERE n < 10
                     ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 -- Deeply nested WITH caused a list-munging problem in v13
 -- Detection of cross-references and self-references
 WITH RECURSIVE w1(c1) AS
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index 835077e9d57..1ce7826cf90 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -110,22 +110,26 @@ select '1'::xid < '2'::xid;
 ERROR:  operator does not exist: xid < xid
 LINE 1: select '1'::xid < '2'::xid;
                         ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 select '1'::xid <= '2'::xid;
 ERROR:  operator does not exist: xid <= xid
 LINE 1: select '1'::xid <= '2'::xid;
                         ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 select '1'::xid > '2'::xid;
 ERROR:  operator does not exist: xid > xid
 LINE 1: select '1'::xid > '2'::xid;
                         ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 select '1'::xid >= '2'::xid;
 ERROR:  operator does not exist: xid >= xid
 LINE 1: select '1'::xid >= '2'::xid;
                         ^
-HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL:  No operator of that name accepts the given argument types.
+HINT:  You might need to add explicit type casts.
 -- we want them for xid8 though
 select '1'::xid8 < '2'::xid8, '2'::xid8 < '2'::xid8, '2'::xid8 < '1'::xid8;
  ?column? | ?column? | ?column? 
-- 
2.43.7

