On 2025-Nov-27, Peter Geoghegan wrote:

> On Thu, Nov 27, 2025 at 11:00 AM Álvaro Herrera <[email protected]> wrote:

> index_elems is needed by ON CONFLICT so that the user can specify an
> operator class and/or a collation. This is probably hardly ever used,
> but it does have its place.

Right.

> > So what about the attached patch?  I ran all tests and everything seems
> > to work correctly.  (Maybe I'd add some tests to verify that this
> > new error is covered, as the ones just above.)  It would complain to the
> > above:
> 
> Seems reasonable to me.

Pushed, thanks for looking.

While looking at the test output, I wondered if it would be useful to
make the error cursor point to the bogus element itself rather than to
the overall InferClause.  At the moment it doesn't look terribly useful,
so I'm parking this patch here; but if somebody were to be motivated to,
say, patch ComputeIndexAttrs to have a ParseState, we could add error
location to the ereports there.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"Before you were born your parents weren't as boring as they are now. They
got that way paying your bills, cleaning up your room and listening to you
tell them how idealistic you are."  -- Charles J. Sykes' advice to teenagers
>From 0a4a5ae8830dd411237e0221b58aaa554aa3b97b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <[email protected]>
Date: Fri, 12 Dec 2025 14:22:00 +0100
Subject: [PATCH] add Location to IndexElem

---
 src/backend/nodes/nodeFuncs.c     | 3 +++
 src/backend/parser/gram.y         | 5 +++++
 src/backend/parser/parse_clause.c | 8 ++++----
 src/include/nodes/parsenodes.h    | 1 +
 4 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 024a2b2fd84..89b7d80c0aa 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1726,6 +1726,9 @@ exprLocation(const Node *expr)
 		case T_ColumnDef:
 			loc = ((const ColumnDef *) expr)->location;
 			break;
+		case T_IndexElem:
+			loc = ((const IndexElem *) expr)->location;
+			break;
 		case T_Constraint:
 			loc = ((const Constraint *) expr)->location;
 			break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7856ce9d78f..a9bad1bff04 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -8402,6 +8402,7 @@ index_elem_options:
 			$$->opclassopts = NIL;
 			$$->ordering = $3;
 			$$->nulls_ordering = $4;
+			$$->location = @1;
 		}
 	| opt_collate any_name reloptions opt_asc_desc opt_nulls_order
 		{
@@ -8414,6 +8415,7 @@ index_elem_options:
 			$$->opclassopts = $3;
 			$$->ordering = $4;
 			$$->nulls_ordering = $5;
+			$$->location = @1;
 		}
 	;
 
@@ -8426,16 +8428,19 @@ index_elem: ColId index_elem_options
 				{
 					$$ = $2;
 					$$->name = $1;
+					$$->location = @1;
 				}
 			| func_expr_windowless index_elem_options
 				{
 					$$ = $2;
 					$$->expr = $1;
+					$$->location = @1;
 				}
 			| '(' a_expr ')' index_elem_options
 				{
 					$$ = $4;
 					$$->expr = $2;
+					$$->location = @1;
 				}
 		;
 
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 57609e2d55c..34693c8a9e6 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -3289,20 +3289,20 @@ resolve_unique_index_expr(ParseState *pstate, InferClause *infer,
 					 errmsg("%s is not allowed in ON CONFLICT clause",
 							"ASC/DESC"),
 					 parser_errposition(pstate,
-										exprLocation((Node *) infer))));
+										exprLocation((Node *) ielem))));
 		if (ielem->nulls_ordering != SORTBY_NULLS_DEFAULT)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
 					 errmsg("%s is not allowed in ON CONFLICT clause",
 							"NULLS FIRST/LAST"),
 					 parser_errposition(pstate,
-										exprLocation((Node *) infer))));
+										exprLocation((Node *) ielem))));
 		if (ielem->opclassopts)
 			ereport(ERROR,
 					errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
 					errmsg("operator class options are not allowed in ON CONFLICT clause"),
 					parser_errposition(pstate,
-									   exprLocation((Node *) infer)));
+									   exprLocation((Node *) ielem)));
 
 		if (!ielem->expr)
 		{
@@ -3342,7 +3342,7 @@ resolve_unique_index_expr(ParseState *pstate, InferClause *infer,
 			pInfer->infercollid = InvalidOid;
 		else
 			pInfer->infercollid = LookupCollation(pstate, ielem->collation,
-												  exprLocation(pInfer->expr));
+												  exprLocation((Node *) ielem));
 
 		if (!ielem->opclass)
 			pInfer->inferopclass = InvalidOid;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d14294a4ece..48738aa26f0 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -816,6 +816,7 @@ typedef struct IndexElem
 	List	   *opclassopts;	/* opclass-specific options, or NIL */
 	SortByDir	ordering;		/* ASC/DESC/default */
 	SortByNulls nulls_ordering; /* FIRST/LAST/default */
+	ParseLoc	location;		/* token location, or -1 if unknown */
 } IndexElem;
 
 /*
-- 
2.47.3

Reply via email to