From 58cecd196460d12b0257f90a47acb4f6d6912afc Mon Sep 17 00:00:00 2001 From: Matthys Strydom Date: Tue, 10 Nov 2026 03:25:47 +0000 Subject: [PATCH] Report malformed integer aggregate states as array errors Several SQL-callable aggregate support functions take an int8[] transition state. They used elog(ERROR) when the state did not contain the expected two elements. This assigned ERRCODE_INTERNAL_ERROR, so a direct call such as int8_avg(ARRAY[1]::int8[]) reported SQLSTATE XX000 for invalid user input. Use ERRCODE_ARRAY_SUBSCRIPT_ERROR instead, consistent with other code that rejects arrays with an invalid shape. Add a regression test for the SQLSTATE. --- src/backend/utils/adt/numeric.c | 32 ++++++++++++++++++------ src/test/regress/expected/aggregates.out | 5 ++++ src/test/regress/sql/aggregates.sql | 5 ++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 7deea2046f1..cb64feccffb 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -6476,7 +6476,9 @@ int2_avg_accum(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); @@ -6511,7 +6513,9 @@ int4_avg_accum(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); @@ -6543,11 +6547,15 @@ int4_avg_combine(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray1) || ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); if (ARR_HASNULL(transarray2) || ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1); state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2); @@ -6582,7 +6590,9 @@ int2_avg_accum_inv(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); transdata->count--; @@ -6610,7 +6620,9 @@ int4_avg_accum_inv(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); transdata->count--; @@ -6629,7 +6641,9 @@ int8_avg(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); /* SQL defines AVG of no values to be NULL */ @@ -6654,7 +6668,9 @@ int2int4_sum(PG_FUNCTION_ARGS) if (ARR_HASNULL(transarray) || ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - elog(ERROR, "expected 2-element int8 array"); + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); /* SQL defines SUM of no values to be NULL */ diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index ce555a31693..3d67040c7ee 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -25,6 +25,11 @@ SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; 32.6666666666666667 (1 row) +-- verify malformed aggregate transition states use a data exception SQLSTATE +\set VERBOSITY sqlstate +SELECT int8_avg(ARRAY[1]::int8[]); +ERROR: 2202E +\set VERBOSITY default SELECT any_value(v) FROM (VALUES (1), (2), (3)) AS v (v); any_value ----------- diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 0936088b074..4d9d294da51 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -24,6 +24,11 @@ SELECT avg(four) AS avg_1 FROM onek; SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; +-- verify malformed aggregate transition states use a data exception SQLSTATE +\set VERBOSITY sqlstate +SELECT int8_avg(ARRAY[1]::int8[]); +\set VERBOSITY default + SELECT any_value(v) FROM (VALUES (1), (2), (3)) AS v (v); SELECT any_value(v) FROM (VALUES (NULL)) AS v (v); SELECT any_value(v) FROM (VALUES (NULL), (1), (2)) AS v (v); -- 2.50.1