v1-0003-Experiment-without-a-dedicated-hasnulls-loop.patch
text/plain
Filename: v1-0003-Experiment-without-a-dedicated-hasnulls-loop.patch
Type: text/plain
Part: 5
Message:
More speedups for tuple deformation
From 8064b149dbf465d8b17a8b2aed35b6b079262860 Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sat, 27 Dec 2025 20:54:16 +1300
Subject: [PATCH v1 3/3] Experiment without a dedicated !hasnulls loop
This makes the code smaller and seems to make some tests go faster
---
src/backend/executor/execTuples.c | 76 ++++++++++---------------------
1 file changed, 24 insertions(+), 52 deletions(-)
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 18e7db12dab..d6e9c91adaa 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -1050,7 +1050,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
else
{
bp = NULL;
- nextNullAttr = natts;
+ nextNullSeqEnd = nextNullAttr = natts;
}
#ifdef OPTIMIZE_BYVAL
@@ -1129,15 +1129,21 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
off = *offp;
}
- /* Handle the remaining part of the tuple. */
- if (!hasnulls)
+ /*
+ * Handle the remaining part of the tuple. Rather than going to the
+ * trouble of calling att_isnull(), we instead do some processing on the
+ * bit mask to find the next NULL bit and how many follow that then
+ * process using two loops, the first of the inner loops here never sees a
+ * NULL attribute as the loop will end before we get to a NULL attr, the
+ * 2nd loop takes over and processes all the NULLs and we'll go back to
+ * the first loop and handle any remaining non-NULL attributes.
+ */
+ for (;;)
{
- /*
- * If there are no NULLs before natts, then use a simple loop without
- * NULL handling.
- */
- for (; attnum < natts; attnum++)
+ for (; attnum < nextNullAttr; attnum++)
{
+ Assert(!att_isnull(attnum, bp));
+
cattr = TupleDescCompactAttr(tupleDesc, attnum);
/* align the offset for this attribute */
@@ -1152,53 +1158,19 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
/* move the offset beyond this attribute */
off = att_addlength_pointer(off, cattr->attlen, tp + off);
}
- }
- else
- {
- /*
- * Otherwise, we need to handle NULLs. Rather than going to the
- * trouble of calling att_isnull(), we instead do some processing on
- * the bit mask to find the next NULL bit and how many follow that
- * then process using two loops, the first of the inner loops here
- * never sees a NULL attribute as the loop will end before we get to a
- * NULL attr, the 2nd loop takes over and processes all the NULLs and
- * we'll go back to the first loop and handle any remaining non-NULL
- * attributes.
- */
- for (;;)
- {
- for (; attnum < nextNullAttr; attnum++)
- {
- Assert(!att_isnull(attnum, bp));
- cattr = TupleDescCompactAttr(tupleDesc, attnum);
-
- /* align the offset for this attribute */
- off = att_pointer_alignby(off,
- cattr->attalignby,
- cattr->attlen,
- tp + off);
-
- values[attnum] = fetchatt(cattr, tp + off);
- isnull[attnum] = false;
-
- /* move the offset beyond this attribute */
- off = att_addlength_pointer(off, cattr->attlen, tp + off);
- }
-
- if (likely(attnum == natts))
- break;
-
- /* Handle the NULLs */
- for (; unlikely(attnum < nextNullSeqEnd); attnum++)
- {
- Assert(att_isnull(attnum, bp));
- isnull[attnum] = true;
- }
+ if (likely(attnum == natts))
+ break;
- /* Locate the next NULL, if any */
- next_null_until(bp, attnum, natts, &nextNullAttr, &nextNullSeqEnd);
+ /* Handle the NULLs */
+ for (; unlikely(attnum < nextNullSeqEnd); attnum++)
+ {
+ Assert(att_isnull(attnum, bp));
+ isnull[attnum] = true;
}
+
+ /* Locate the next NULL, if any */
+ next_null_until(bp, attnum, natts, &nextNullAttr, &nextNullSeqEnd);
}
/*
--
2.43.0