Skip to content

Conversation

@gburd
Copy link
Owner

@gburd gburd commented Dec 1, 2025

No description provided.

gburd added 4 commits December 1, 2025 10:23
This commit provides a set of macros that should be used when inserting
or updating tuples.  These macros help declare state necessary when
tracking updates and forming new tuples.  There are macros used to set
fields to new values or to NULL.  Finally there are macros for inserting
or updating these tuples.

There are a few reasons to standardize catalog modification code and
move it away from direct Form/GETSTRUCT or values/nulls/replaces-style
access.  First, these models can be error prone and require attention to
a variety of details that can easily be overlooked.  Second, at present
while we know what fields are modified we don't preserve that
information and pass it on to the heap_update() code.  Third, at some
point we'll need in-memory representations completely decoupled from the
disk to support upgradeable catalogs.

Previous this patch there are two methods for accomplishing this task;
Form/GETSTRUCT, and values/nulls/replaces. This new method provides a
more intuitive and less error-prone approach without changing the
fundamentals of the process, meaning this should remain backward
compatible.  It is now possible to retain knowledge of the set of
mutated attributes when working with catalog tuples.  A follow-on patch
will use this to avoid the overhead of HeapDetermineColumnsInfo() in
heap_update() where (while holding a lock) we re-discover the set of
modified by comparing old/new HeapTuple Datums when trying to identify
indexed attributes that have new values and should prevent HOT updates.

The "Form/GETSTRUCT" model allows for direct access to the tuple data
that is then modified, copied, and then updated via
CatalogTupleUpdate().

Old:
  Form_pg_index form = (Form_pg_index) GETSTRUCT(tuple);

  form->inisclustered = false;
  CatalogTupleUpdate(relation, &tuple->t_self, tuple);

New:
  CatalogUpdateFieldContext(pg_index, ctx);
  CatalogSetForm(pg_index, ctx, tuple);

  CatalogTupleUpdateField(ctx, pg_index, indisclustered, false);
  ModifyCatalogTupleField(relation, tuple, ctx);

The "values/nulls/replaces" model collects the necessary information to
either update or create a heap tuple using heap_modify_tuple() or
heap_form_tuple() or sometimes heap_modify_tuple_by_cols().  While all
those functions remain unchanged and can be used there is a new model.

Old:
  bool    nulls[Natts_pg_type];
  bool    replaces[Natts_pg_type];
  Datum   values[Natts_pg_type];

  values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
  nulls[Anum_pg_type_typdefaultbin - 1] = true;
  replaces[Anum_pg_type_oid - 1] = false;

  tup = heap_modify_tuple(tuple, desc, values, nulls, replaces);

  CatalogTupleUpdate(relation, &tuple->t_self, tuple);

New:
  CatalogUpdateValuesContext(pg_type, ctx);

  CatalogTupleUpdateValue(ctx, pg_type, typtype, CharGetDatum(typeType));
  ModifyCatalogTupleValues(relation, tuple, ctx);

The heap_update_tuple() function is functionally equivalent to
heap_modify_tuple(), but takes a Bitmapset called "updated" rather than
an array of bool generally called "replaces" as a method for indicating
what was modified.  Additionally, this new function tries to balance the
tradeoffs of calling heap_getattr() versus heap_deform_tuple() based
on the ratio of attributes updated and their known runtime complexities.
Both paths are functionally equivalent.

The changes also include initialization of the values/nulls arrays
rather than loops or memset().

There is no impact to non-catalog related paths.
Apply all necessary changes to use the new macros for catalog tuples.
This commit finishes the work started in the previous one.  There should
be no behavioral changes resulting from these commits.
This commit refactors the interaction between heap_tuple_update(),
heap_update(), and simple_heap_update() to improve code organization and
flexibility. The changes are functionally equivalent to the previous
implementation except that now catalog tuples no longer depends on
HeapDetermineColumnsInfo() to determine which attributes changed, that
information is supplied to simple_heap_update().

As part of this reorganization, the handling of replica identity key
attributes has been adjusted. Instead of fetching a second copy of
the bitmap during an update operation, the caller is now required to
provide it. This change applies to both heap_update() and
heap_delete().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants