From 813bf7084c9e1a2161a2e97dd57906d3c2dcaf20 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Tue, 20 Oct 2026 13:41:32 +1300 Subject: [PATCH v4 1/2] Add PG_RETURN_ARG macro and use it for sum(int2) and sum(int4) This is intended for SQL-level functions written in C for cases when they want to return an input parameter unmodified; NULL if that parameter is NULL, or the exact value of the parameter otherwise. The return type and the given input parameter must have matching types. The caller must verify whether it's safe to not copy non-byval types and not de-toast variable-length typed inputs. Here we introduce two usages of the new macro for the transition functions for sum(int4) and sum(int2). These just need to return the int8 aggregate state value unmodified when asked to transition a NULL input; the aggregate state may or may not be NULL at that point. PG_RETURN_ARG() is coded to work for either case. This is primarily being added to partially circumvent an argument against adding overflow checks on sum(int2) and sum(int4), which a pending patch proposes to do. Effectively, here we're removing 1 jump per transition function, and that commit plans to add a new jump, so this commit allows a net zero increase in jumps for both of those functions. Author: David Rowley Reviewed-by: Tom Lane Discussion: https://postgr.es/m/CAApHDvp-3v1OWbo7RavBf37=MjNScqhj4vyAyHOUDY51nGUnog@mail.gmail.com --- src/backend/utils/adt/numeric.c | 38 ++++++++++++--------------------- src/include/fmgr.h | 13 +++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 405cea6b6a6..338add18344 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -6357,22 +6357,20 @@ int2_sum(PG_FUNCTION_ARGS) int64 oldsum; int64 newval; + if (PG_ARGISNULL(1)) + { + /* NULL value being aggregated, so return state unchanged */ + PG_RETURN_ARG(0); + } + if (PG_ARGISNULL(0)) { - /* No non-null input seen so far... */ - if (PG_ARGISNULL(1)) - PG_RETURN_NULL(); /* still no non-null */ /* This is the first non-null input. */ - newval = (int64) PG_GETARG_INT16(1); - PG_RETURN_INT64(newval); + PG_RETURN_INT64((int64) PG_GETARG_INT16(1)); } oldsum = PG_GETARG_INT64(0); - /* Leave sum unchanged if new input is null. */ - if (PG_ARGISNULL(1)) - PG_RETURN_INT64(oldsum); - /* OK to do the addition. */ newval = oldsum + (int64) PG_GETARG_INT16(1); @@ -6385,22 +6383,20 @@ int4_sum(PG_FUNCTION_ARGS) int64 oldsum; int64 newval; + if (PG_ARGISNULL(1)) + { + /* NULL value being aggregated, so return state unchanged */ + PG_RETURN_ARG(0); + } + if (PG_ARGISNULL(0)) { - /* No non-null input seen so far... */ - if (PG_ARGISNULL(1)) - PG_RETURN_NULL(); /* still no non-null */ /* This is the first non-null input. */ - newval = (int64) PG_GETARG_INT32(1); - PG_RETURN_INT64(newval); + PG_RETURN_INT64((int64) PG_GETARG_INT32(1)); } oldsum = PG_GETARG_INT64(0); - /* Leave sum unchanged if new input is null. */ - if (PG_ARGISNULL(1)) - PG_RETURN_INT64(oldsum); - /* OK to do the addition. */ newval = oldsum + (int64) PG_GETARG_INT32(1); @@ -6424,12 +6420,6 @@ int8_sum(PG_FUNCTION_ARGS) PG_RETURN_NUMERIC(int64_to_numeric(PG_GETARG_INT64(1))); } - /* - * Note that we cannot special-case the aggregate case here, as we do for - * int2_sum and int4_sum: numeric is of variable size, so we cannot modify - * our first parameter in-place. - */ - oldsum = PG_GETARG_NUMERIC(0); /* Leave sum unchanged if new input is null. */ diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 04b7914095f..cd87fd87986 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -349,6 +349,19 @@ extern varlena *pg_detoast_datum_packed(varlena *datum); /* A few internal functions return void (which is not the same as NULL!) */ #define PG_RETURN_VOID() return (Datum) 0 +/* + * A shortcut to allow functions to return the value of the given input + * parameter, NULL if that parameter was NULL, and the value of the parameter + * otherwise. The caller is responsible for ensuring the types match and + * that it's safe to return non-byval inputs without making a copy or + * detoasting variable-length types. + */ +#define PG_RETURN_ARG(n) \ + do { \ + fcinfo->isnull = fcinfo->args[n].isnull; \ + return fcinfo->args[n].value; \ + } while (0) + /* Macros for returning results of standard types */ #define PG_RETURN_DATUM(x) return (x) -- 2.53.0