Copy-Paste Error in hash_record_extended() — args[1].isnull Not Set
Core Problem
A straightforward but potentially consequential copy-paste bug exists in src/backend/utils/adt/rowtypes.c within the hash_record_extended() function. When setting up the FunctionCallInfo (locfcinfo) arguments for invoking an element's extended hash function, the code incorrectly sets args[0].isnull = false twice instead of setting args[1].isnull = false for the seed argument.
The Buggy Code Pattern
locfcinfo->args[0].value = values[i];
locfcinfo->args[0].isnull = false;
locfcinfo->args[1].value = Int64GetDatum(seed);
locfcinfo->args[0].isnull = false; /* BUG: should be args[1] */
The fix changes the last line to locfcinfo->args[1].isnull = false;.
Why This Matters Architecturally
Extended Hashing in PostgreSQL
The hash_record_extended() function implements extended hashing for composite types (row types). It is part of PostgreSQL's support for hash-based operations (hash joins, hash aggregation, hash indexes) on composite/record types. The "extended" hash variant takes a 64-bit seed parameter (the second argument, args[1]) which is used to produce hash values that can be combined or varied — critical for hash partitioning and parallel hash operations.
Why the Bug Hasn't Caused Visible Failures
The reason this bug likely hasn't caused crashes or incorrect results in practice is:
InitFunctionCallInfoDatazeroes the structure — Whenlocfcinfois initialized, theisnullfields are typically zeroed out (false), soargs[1].isnullis alreadyfalsebefore this code runs.- The function is called in a loop — For each field of the composite type, the same
locfcinfois reused. Sinceargs[1].isnullwas never set totrueby any code path, it remainsfalsethroughout. - Hash functions don't typically check isnull for the seed — Most hash support functions assume the seed is always non-null.
Despite being harmless in practice due to zero-initialization, this is a correctness issue: the code's intent is clearly to set args[1].isnull = false, and relying on implicit zero-initialization is fragile and misleading to readers.
Origin
Michael Paquier identifies commit 01e658fa74cb as the source. This commit introduced the extended hash support for record types, and the copy-paste error has persisted since then — indicating it was introduced when the developer copied the args[0] initialization pattern and forgot to update the index for the second line of the args[1] block.
Proposed Solution
The fix is a single-character change: args[0] → args[1] on the relevant line. This is unambiguous and requires no design discussion.
Resolution Status
Michael Paquier (a committer) acknowledges the fix is clearly correct but notes it should wait until after the current code freeze period ends. This is appropriate for a low-risk cosmetic/correctness fix that has no behavioral impact — it should not be part of a release-critical window.
Broader Pattern
This type of copy-paste error in FunctionCallInfo argument setup is a known hazard in PostgreSQL's function call infrastructure. The repetitive pattern of setting .value and .isnull for each argument slot is error-prone. The relatively modern FunctionCallInfoBaseData (introduced in PG12 via commit that restructured fmgr) with its args array is cleaner than the old approach but still susceptible to index errors.