public inbox for [email protected]
help / color / mirror / Atom feedFrom: jian he <[email protected]>
To: Amul Sul <[email protected]>
Cc: PostgreSQL-development <[email protected]>
Subject: Re: Error position support for ComputeIndexAttrs
Date: Wed, 31 Dec 2025 16:13:47 +0800
Message-ID: <CACJufxHQLuROz_1MjuvNSp+QgtLfNH_noiq18mZBhB8Mk01_=g@mail.gmail.com> (raw)
In-Reply-To: <CAAJ_b95FOL6uEUb6p4=ho7Bj=HFBpzhRh5G0G2--YH9qHxt0rw@mail.gmail.com>
References: <CACJufxH3OgXF1hrzGAaWyNtye2jHEmk9JbtrtGv-KJK6tsGo5w@mail.gmail.com>
<CAAJ_b95FOL6uEUb6p4=ho7Bj=HFBpzhRh5G0G2--YH9qHxt0rw@mail.gmail.com>
On Tue, Dec 16, 2025 at 9:01 PM Amul Sul <[email protected]> wrote:
> >
>
> +1, patch looks quite straightforward and pretty much reasonable to me.
>
> Regards,
> Amul
hi.
some failures because I didn't adjust collate.linux.utf8.out and
collate.windows.win1252.out:
https://cirrus-ci.com/build/6690791764000768
https://api.cirrus-ci.com/v1/artifact/task/5658162642026496/testrun/build/testrun/regress/regress/re...
https://api.cirrus-ci.com/v1/artifact/task/5605386083893248/log/src/test/regress/regression.diffs
The attached patch only adjusts collate.linux.utf8.out and
collate.windows.win1252.out, with no other changes.
--
jian
https://www.enterprisedb.com
Attachments:
[text/x-patch] v2-0002-Error-position-support-for-index-specifications.patch (27.8K, ../CACJufxHQLuROz_1MjuvNSp+QgtLfNH_noiq18mZBhB8Mk01_=g@mail.gmail.com/2-v2-0002-Error-position-support-for-index-specifications.patch)
download | inline diff:
From 2cbd83fd0cc6683a6cf0066cb8556639db939bfb Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Wed, 31 Dec 2025 13:36:44 +0800
Subject: [PATCH v2 2/2] Error position support for index specifications
Add support for error position reporting for index specifications.
comitfest: https://commitfest.postgresql.org/patch/6322
discussion: https://postgr.es/m/CACJufxH3OgXF1hrzGAaWyNtye2jHEmk9JbtrtGv-KJK6tsGo5w@mail.gmail.com
---
src/backend/bootstrap/bootparse.y | 6 +-
src/backend/commands/indexcmds.c | 60 ++++++++++++-------
src/backend/commands/tablecmds.c | 9 ++-
src/backend/tcop/utility.c | 3 +-
src/include/commands/defrem.h | 3 +-
src/test/regress/expected/alter_table.out | 4 ++
.../regress/expected/collate.icu.utf8.out | 2 +
.../regress/expected/collate.linux.utf8.out | 2 +
src/test/regress/expected/collate.out | 2 +
.../expected/collate.windows.win1252.out | 2 +
src/test/regress/expected/insert_conflict.out | 6 +-
.../regress/expected/sqljson_queryfuncs.out | 56 +++++++++++++++++
12 files changed, 125 insertions(+), 30 deletions(-)
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index da0e7dea497..063faecadc1 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -308,7 +308,8 @@ Boot_DeclareIndexStmt:
relationId = RangeVarGetRelid(stmt->relation, NoLock,
false);
- DefineIndex(relationId,
+ DefineIndex(NULL,
+ relationId,
stmt,
$4,
InvalidOid,
@@ -361,7 +362,8 @@ Boot_DeclareUniqueIndexStmt:
relationId = RangeVarGetRelid(stmt->relation, NoLock,
false);
- DefineIndex(relationId,
+ DefineIndex(NULL,
+ relationId,
stmt,
$5,
InvalidOid,
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 67a451463ed..ef564e9e3bf 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -75,7 +75,8 @@
/* non-export function prototypes */
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts);
static void CheckPredicate(Expr *predicate);
-static void ComputeIndexAttrs(IndexInfo *indexInfo,
+static void ComputeIndexAttrs(ParseState *pstate,
+ IndexInfo *indexInfo,
Oid *typeOids,
Oid *collationOids,
Oid *opclassOids,
@@ -248,7 +249,7 @@ CheckIndexCompatible(Oid oldId,
opclassIds = palloc_array(Oid, numberOfAttributes);
opclassOptions = palloc_array(Datum, numberOfAttributes);
coloptions = palloc_array(int16, numberOfAttributes);
- ComputeIndexAttrs(indexInfo,
+ ComputeIndexAttrs(NULL, indexInfo,
typeIds, collationIds, opclassIds, opclassOptions,
coloptions, attributeList,
exclusionOpNames, relationId,
@@ -515,6 +516,7 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
* consider offering one DDL command for catalog setup and a separate DDL
* command for steps that run opaque expressions.
*
+ * 'pstate': pointer to ParseState struct for determining error position
* 'tableId': the OID of the table relation on which the index is to be
* created
* 'stmt': IndexStmt describing the properties of the new index.
@@ -538,7 +540,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
* Returns the object address of the created index.
*/
ObjectAddress
-DefineIndex(Oid tableId,
+DefineIndex(ParseState *pstate,
+ Oid tableId,
IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
@@ -933,7 +936,8 @@ DefineIndex(Oid tableId,
opclassIds = palloc_array(Oid, numberOfAttributes);
opclassOptions = palloc_array(Datum, numberOfAttributes);
coloptions = palloc_array(int16, numberOfAttributes);
- ComputeIndexAttrs(indexInfo,
+ ComputeIndexAttrs(pstate,
+ indexInfo,
typeIds, collationIds, opclassIds, opclassOptions,
coloptions, allIndexParams,
stmt->excludeOpNames, tableId,
@@ -1517,7 +1521,8 @@ DefineIndex(Oid tableId,
SetUserIdAndSecContext(root_save_userid,
root_save_sec_context);
childAddr =
- DefineIndex(childRelid, childStmt,
+ DefineIndex(NULL,
+ childRelid, childStmt,
InvalidOid, /* no predefined OID */
indexRelationId, /* this is our child */
createdConstraintId,
@@ -1866,7 +1871,8 @@ CheckPredicate(Expr *predicate)
* InvalidOid, and other ddl_* arguments are undefined.
*/
static void
-ComputeIndexAttrs(IndexInfo *indexInfo,
+ComputeIndexAttrs(ParseState *pstate,
+ IndexInfo *indexInfo,
Oid *typeOids,
Oid *collationOids,
Oid *opclassOids,
@@ -1951,12 +1957,14 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" named in key does not exist",
- attribute->name)));
+ attribute->name)),
+ parser_errposition(pstate, exprLocation((Node *) attribute)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" does not exist",
- attribute->name)));
+ attribute->name)),
+ parser_errposition(pstate, exprLocation((Node *) attribute)));
}
attform = (Form_pg_attribute) GETSTRUCT(atttuple);
indexInfo->ii_IndexAttrNumbers[attn] = attform->attnum;
@@ -1974,7 +1982,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
if (attn >= nkeycols)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("expressions are not supported in included columns")));
+ errmsg("expressions are not supported in included columns"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
atttype = exprType(expr);
attcollation = exprCollation(expr);
@@ -2015,7 +2024,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
if (contain_mutable_functions_after_planning((Expr *) expr))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("functions in index expression must be marked IMMUTABLE")));
+ errmsg("functions in index expression must be marked IMMUTABLE"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
}
}
@@ -2030,19 +2040,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
if (attribute->collation)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("including column does not support a collation")));
+ errmsg("including column does not support a collation"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
if (attribute->opclass)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("including column does not support an operator class")));
+ errmsg("including column does not support an operator class"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
if (attribute->ordering != SORTBY_DEFAULT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("including column does not support ASC/DESC options")));
+ errmsg("including column does not support ASC/DESC options"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("including column does not support NULLS FIRST/LAST options")));
+ errmsg("including column does not support NULLS FIRST/LAST options"),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
opclassOids[attn] = InvalidOid;
opclassOptions[attn] = (Datum) 0;
@@ -2086,7 +2100,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
ereport(ERROR,
(errcode(ERRCODE_INDETERMINATE_COLLATION),
errmsg("could not determine which collation to use for index expression"),
- errhint("Use the COLLATE clause to set the collation explicitly.")));
+ errhint("Use the COLLATE clause to set the collation explicitly."),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
}
else
{
@@ -2094,7 +2109,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("collations are not supported by type %s",
- format_type_be(atttype))));
+ format_type_be(atttype)),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
}
collationOids[attn] = attcollation;
@@ -2162,7 +2178,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("operator %s is not commutative",
format_operator(opid)),
- errdetail("Only commutative operators can be used in exclusion constraints.")));
+ errdetail("Only commutative operators can be used in exclusion constraints."),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
/*
* Operator must be a member of the right opfamily, too
@@ -2175,7 +2192,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
errmsg("operator %s is not a member of operator family \"%s\"",
format_operator(opid),
get_opfamily_name(opfamily, false)),
- errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
+ errdetail("The exclusion operator must be related to the index operator class for the constraint."),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
indexInfo->ii_ExclusionOps[attn] = opid;
indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
@@ -2225,12 +2243,14 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support ASC/DESC options",
- accessMethodName)));
+ accessMethodName),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
- accessMethodName)));
+ accessMethodName),
+ parser_errposition(pstate, exprLocation((Node *) attribute))));
}
/* Set up the per-column opclass options (attoptions field). */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1d9565b09fc..32be3d3ca75 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1302,7 +1302,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
idxstmt =
generateClonedIndexStmt(NULL, idxRel,
attmap, &constraintOid);
- DefineIndex(RelationGetRelid(rel),
+ DefineIndex(NULL,
+ RelationGetRelid(rel),
idxstmt,
InvalidOid,
RelationGetRelid(idxRel),
@@ -9666,7 +9667,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
/* suppress notices when rebuilding existing index */
quiet = is_rebuild;
- address = DefineIndex(RelationGetRelid(rel),
+ address = DefineIndex(NULL,
+ RelationGetRelid(rel),
stmt,
InvalidOid, /* no predefined OID */
InvalidOid, /* no parent index */
@@ -20770,7 +20772,8 @@ AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
stmt = generateClonedIndexStmt(NULL,
idxRel, attmap,
&conOid);
- DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
+ DefineIndex(NULL,
+ RelationGetRelid(attachrel), stmt, InvalidOid,
RelationGetRelid(idxRel),
conOid,
-1,
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index d18a3a60a46..b611eab0550 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1541,7 +1541,8 @@ ProcessUtilitySlow(ParseState *pstate,
/* ... and do it */
EventTriggerAlterTableStart(parsetree);
address =
- DefineIndex(relid, /* OID of heap relation */
+ DefineIndex(pstate,
+ relid, /* OID of heap relation */
stmt,
InvalidOid, /* no predefined OID */
InvalidOid, /* no parent index */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index f3432b4b6a1..39afce90707 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -25,7 +25,8 @@
extern void RemoveObjects(DropStmt *stmt);
/* commands/indexcmds.c */
-extern ObjectAddress DefineIndex(Oid tableId,
+extern ObjectAddress DefineIndex(ParseState *pstate,
+ Oid tableId,
IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 5e98bbf2425..ac1a7345d0f 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -1585,8 +1585,12 @@ ERROR: column "........pg.dropped.1........" referenced in foreign key constrai
drop table atacc2;
create index "testing_idx" on atacc1(a);
ERROR: column "a" does not exist
+LINE 1: create index "testing_idx" on atacc1(a);
+ ^
create index "testing_idx" on atacc1("........pg.dropped.1........");
ERROR: column "........pg.dropped.1........" does not exist
+LINE 1: create index "testing_idx" on atacc1("........pg.dropped.1.....
+ ^
-- test create as and select into
insert into atacc1 values (21, 22, 23);
create table attest1 as select * from atacc1;
diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out
index 8023014fe63..1325e123877 100644
--- a/src/test/regress/expected/collate.icu.utf8.out
+++ b/src/test/regress/expected/collate.icu.utf8.out
@@ -996,6 +996,8 @@ CREATE INDEX collate_test1_idx3 ON collate_test1 ((b COLLATE "C")); -- this is d
CREATE INDEX collate_test1_idx4 ON collate_test1 (((b||'foo') COLLATE "POSIX"));
CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE "C"); -- fail
ERROR: collations are not supported by type integer
+LINE 1: CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE ...
+ ^
CREATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C")); -- fail
ERROR: collations are not supported by type integer
LINE 1: ...ATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C...
diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out
index fbaab7cdf83..c6e84c27b69 100644
--- a/src/test/regress/expected/collate.linux.utf8.out
+++ b/src/test/regress/expected/collate.linux.utf8.out
@@ -1009,6 +1009,8 @@ CREATE INDEX collate_test1_idx3 ON collate_test1 ((b COLLATE "C")); -- this is d
CREATE INDEX collate_test1_idx4 ON collate_test1 (((b||'foo') COLLATE "POSIX"));
CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE "C"); -- fail
ERROR: collations are not supported by type integer
+LINE 1: CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE ...
+ ^
CREATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C")); -- fail
ERROR: collations are not supported by type integer
LINE 1: ...ATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C...
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index bf72908fbd3..25818f09ad2 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -596,6 +596,8 @@ CREATE INDEX collate_test1_idx3 ON collate_test1 ((b COLLATE "POSIX")); -- this
CREATE INDEX collate_test1_idx4 ON collate_test1 (((b||'foo') COLLATE "POSIX"));
CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE "POSIX"); -- fail
ERROR: collations are not supported by type integer
+LINE 1: CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE ...
+ ^
CREATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "POSIX")); -- fail
ERROR: collations are not supported by type integer
LINE 1: ...ATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "P...
diff --git a/src/test/regress/expected/collate.windows.win1252.out b/src/test/regress/expected/collate.windows.win1252.out
index 4644f56b31d..2a9e52a6b4a 100644
--- a/src/test/regress/expected/collate.windows.win1252.out
+++ b/src/test/regress/expected/collate.windows.win1252.out
@@ -845,6 +845,8 @@ CREATE INDEX collate_test1_idx3 ON collate_test1 ((b COLLATE "C")); -- this is d
CREATE INDEX collate_test1_idx4 ON collate_test1 (((b||'foo') COLLATE "POSIX"));
CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE "C"); -- fail
ERROR: collations are not supported by type integer
+LINE 1: CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE ...
+ ^
CREATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C")); -- fail
ERROR: collations are not supported by type integer
LINE 1: ...ATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C...
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;
diff --git a/src/test/regress/expected/sqljson_queryfuncs.out b/src/test/regress/expected/sqljson_queryfuncs.out
index 53145f50f18..d1b4b8d99f4 100644
--- a/src/test/regress/expected/sqljson_queryfuncs.out
+++ b/src/test/regress/expected/sqljson_queryfuncs.out
@@ -1153,69 +1153,125 @@ CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a[0]'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.time()'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.tim...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.date()'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.dat...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.time_tz()'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.tim...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.timestamp()'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.tim...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.timestamp_tz()'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.tim...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.date() < $.time_tz())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.date() < $.time())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.time() < $.time())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.time() < $.time_tz())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp() < $.timestamp_tz())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp_tz() < $.timestamp_tz())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.time() < $.datetime("HH:MI TZH"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.date() < $.datetime("HH:MI TZH"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp() < $.datetime("HH:MI TZH"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp() < $.datetime("HH:MI"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp_tz() < $.datetime("HH:MI TZH"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp_tz() < $.datetime("HH:MI"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.date() < $x' PASSING '12:34'::timetz AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.dat...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.date() < $x' PASSING '1234'::int AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.dat...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.timestamp(2) < $.timestamp(3))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime()'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@ < $.datetime())'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime())'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime() < $.datetime("HH:MI TZH"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("HH:MI TZH"))'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI") < $.datetime("YY-MM-DD HH:MI"))'));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ? (@.datetime("HH:MI TZH") < $.datetime("YY-MM-DD HH:MI"))'));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.a ?...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $x' PASSING '12:34'::timetz AS x));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("HH:MI TZH") < $y' PASSING '12:34'::timetz AS x));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '12:34'::timetz AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.dat...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() < $x' PASSING '1234'::int AS x));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime() ? (@ == $x)' PASSING '12:34'::time AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.dat...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$.datetime("YY-MM-DD") ? (@ == $x)' PASSING '2020-07-14'::date AS x));
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, ...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, 0 to $.a ? (@.datetime() == $x)]' PASSING '12:34'::time AS x));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, ...
+ ^
CREATE INDEX ON test_jsonb_mutability (JSON_QUERY(js, '$[1, $.a ? (@.datetime("HH:MI") == $x)]' PASSING '12:34'::time AS x));
CREATE INDEX ON test_jsonb_mutability (JSON_VALUE(js, '$' DEFAULT random()::int ON ERROR));
ERROR: functions in index expression must be marked IMMUTABLE
+LINE 1: CREATE INDEX ON test_jsonb_mutability (JSON_VALUE(js, '$' DE...
+ ^
-- DEFAULT expression
CREATE OR REPLACE FUNCTION ret_setint() RETURNS SETOF integer AS
$$
--
2.34.1
[text/x-patch] v2-0001-add-Location-to-IndexElem.patch (6.0K, ../CACJufxHQLuROz_1MjuvNSp+QgtLfNH_noiq18mZBhB8Mk01_=g@mail.gmail.com/3-v2-0001-add-Location-to-IndexElem.patch)
download | inline diff:
From 6bd9a9a3b4dbb32ca01cc456ad5e5131c485b367 Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Wed, 31 Dec 2025 16:05:20 +0800
Subject: [PATCH v2 1/2] add Location to IndexElem
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add location information to each IndexElem so that error reporting can precisely
identify the specific invalid element. This is particularly useful for
subsequent refactoring in ComputeIndexAttrs.
Author: Álvaro Herrera <alvherre(at)kurilemu(dot)de>
comitfest: https://commitfest.postgresql.org/patch/6322
discussion: https://postgr.es/m/CACJufxH3OgXF1hrzGAaWyNtye2jHEmk9JbtrtGv-KJK6tsGo5w@mail.gmail.com
---
src/backend/bootstrap/bootparse.y | 1 +
src/backend/nodes/nodeFuncs.c | 3 +++
src/backend/parser/gram.y | 5 +++++
src/backend/parser/parse_clause.c | 8 ++++----
src/backend/parser/parse_utilcmd.c | 4 ++++
src/include/nodes/parsenodes.h | 1 +
6 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 9833f52c1be..da0e7dea497 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 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 28f4e11e30f..3f407e7d00f 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 = @1;
}
| 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 = @1;
}
;
@@ -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 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/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 2b7b084f216..535c4060dd4 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1883,6 +1883,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
int16 opt = source_idx->rd_indoption[keyno];
iparam = makeNode(IndexElem);
+ iparam->location = -1;
if (AttributeNumberIsValid(attnum))
{
@@ -1974,6 +1975,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
keyno);
iparam = makeNode(IndexElem);
+ iparam->location = -1;
if (AttributeNumberIsValid(attnum))
{
@@ -2813,6 +2815,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 +2932,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/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index bc7adba4a0f..b15b937660f 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.34.1
view thread (4+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: Error position support for ComputeIndexAttrs
In-Reply-To: <CACJufxHQLuROz_1MjuvNSp+QgtLfNH_noiq18mZBhB8Mk01_=g@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox