On Thu, 6 Aug 2026 at 11:34, Peter Geoghegan <[email protected]> wrote: > > I had Claude code look for bugs in new Postgres 19 features. It > authored the test case added by the attached patch. The test fails for > me on master (but not on 18) as follows: > > # SELECT x.m0, x::text FROM t_missing_wholerow x ORDER BY 1; > # - m0 | x > # -----+------------ > # - 40 | (5,,40,41) > # - 40 | (6,,40,41) > # + m0 | x > # +----+---------- > # + 40 | (5,,,41) > # + 40 | (6,,,41) > # (2 rows)
Thanks. Looks like the populate_isnull_array() tts_isnull population writes back that the DEFAULT attribute is NULL for attributes greater than what's in the tuple (which is valid as the array is always large enough), but invalid as that might overwrite a tts_isnull value that was set by the missing attribute code path in some a previous pass of deformation for that tuple where we only deformed up to some previous attribute. Probably we can fix it by not doing the tts_isnull array population when we've already got more slot->tts_nvalid attributes than what appear in the tuple. I'll go and think about the best way to add that check with the least amount of overhead... Alternatively, we could rewrite the missing attributes starting at the tuple's natts with each deform iteration, and that would put the extra overhead just into the has-missing-attribute code path. It's probably possible to form some wild case that ends up with some quadratic overhead because only 1 extra attribute is being deformed with each pass, but that plan probably is slow for other reasons anyway, so it might be better doing it that way so as not to add the overhead to the common path. /me goes off to experiment. David
