From: Tom Lane Date: Sun, 4 Jan 2026 18:23:26 +0000 (-0500) Subject: Add parse location to IndexElem. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62299bbd90d69e2273d3e2ba35af5953d20ca037;p=thirdparty%2Fpostgresql.git Add parse location to IndexElem. This patch mostly just fills in the field, although a few error reports in resolve_unique_index_expr() are adjusted to use it. The next commit will add more uses. catversion bump out of an abundance of caution: I'm not sure IndexElem can appear in stored rules, but I'm not sure it can't either. Author: Álvaro Herrera Co-authored-by: jian he Reviewed-by: Tom Lane Discussion: https://postgr.es/m/CACJufxH3OgXF1hrzGAaWyNtye2jHEmk9JbtrtGv-KJK6tsGo5w@mail.gmail.com Discussion: https://postgr.es/m/202512121327.f2zimsr6guso@alvherre.pgsql --- diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 971fd3277ef..d0c3a878526 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -415,6 +415,7 @@ boot_index_param: n->opclass = list_make1(makeString($2)); n->ordering = SORTBY_DEFAULT; n->nulls_ordering = SORTBY_NULLS_DEFAULT; + n->location = -1; $$ = n; } ; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index c7660df92f4..d29664ca5d4 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 9ea81250ce8..713ee5c10a2 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -8454,6 +8454,7 @@ index_elem_options: $$->opclassopts = NIL; $$->ordering = $3; $$->nulls_ordering = $4; + /* location will be filled in index_elem production */ } | opt_collate any_name reloptions opt_asc_desc opt_nulls_order { @@ -8466,6 +8467,7 @@ index_elem_options: $$->opclassopts = $3; $$->ordering = $4; $$->nulls_ordering = $5; + /* location will be filled in index_elem production */ } ; @@ -8478,16 +8480,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 e72e44fa1ea..e35fd25c9bb 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -3288,21 +3288,18 @@ resolve_unique_index_expr(ParseState *pstate, InferClause *infer, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("%s is not allowed in ON CONFLICT clause", "ASC/DESC"), - parser_errposition(pstate, - exprLocation((Node *) infer)))); + parser_errposition(pstate, ielem->location))); 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)))); + parser_errposition(pstate, ielem->location))); 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))); + parser_errposition(pstate, ielem->location)); if (!ielem->expr) { @@ -3342,7 +3339,7 @@ resolve_unique_index_expr(ParseState *pstate, InferClause *infer, pInfer->infercollid = InvalidOid; else pInfer->infercollid = LookupCollation(pstate, ielem->collation, - exprLocation(pInfer->expr)); + ielem->location); if (!ielem->opclass) pInfer->inferopclass = InvalidOid; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 96f442c4145..652f7538c37 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1962,6 +1962,8 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, } } + iparam->location = -1; + index->indexParams = lappend(index->indexParams, iparam); } @@ -1993,6 +1995,8 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, /* Copy the original index column name */ iparam->indexcolname = pstrdup(NameStr(attr->attname)); + iparam->location = -1; + index->indexIncludingParams = lappend(index->indexIncludingParams, iparam); } /* Copy reloptions if any */ @@ -2813,6 +2817,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) iparam->opclassopts = NIL; iparam->ordering = SORTBY_DEFAULT; iparam->nulls_ordering = SORTBY_NULLS_DEFAULT; + iparam->location = -1; index->indexParams = lappend(index->indexParams, iparam); } @@ -2929,6 +2934,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) iparam->collation = NIL; iparam->opclass = NIL; iparam->opclassopts = NIL; + iparam->location = -1; index->indexIncludingParams = lappend(index->indexIncludingParams, iparam); } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 2feec1f7b43..4eb435eb1ec 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202601011 +#define CATALOG_VERSION_NO 202601041 #endif diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 896c4f34cc0..aac4bfc70d9 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; /* diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out index 91fbe91844d..b0e12962088 100644 --- a/src/test/regress/expected/insert_conflict.out +++ b/src/test/regress/expected/insert_conflict.out @@ -5,15 +5,15 @@ create table insertconflicttest(key int4, fruit text); -- invalid clauses insert into insertconflicttest values (1) on conflict (key int4_ops (fillfactor=10)) do nothing; ERROR: operator class options are not allowed in ON CONFLICT clause -LINE 1: ...rt into insertconflicttest values (1) on conflict (key int4_... +LINE 1: ...t into insertconflicttest values (1) on conflict (key int4_o... ^ insert into insertconflicttest values (1) on conflict (key asc) do nothing; ERROR: ASC/DESC is not allowed in ON CONFLICT clause -LINE 1: ...rt into insertconflicttest values (1) on conflict (key asc) ... +LINE 1: ...t into insertconflicttest values (1) on conflict (key asc) d... ^ insert into insertconflicttest values (1) on conflict (key nulls last) do nothing; ERROR: NULLS FIRST/LAST is not allowed in ON CONFLICT clause -LINE 1: ...rt into insertconflicttest values (1) on conflict (key nulls... +LINE 1: ...t into insertconflicttest values (1) on conflict (key nulls ... ^ -- These things should work through a view, as well create view insertconflictview as select * from insertconflicttest;