=== Applying patches on top of PostgreSQL commit ID a93e2a1e25a6d5410abb1446637c4d9a4f24e35d === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sun Jan 12 16:20:24 UTC 2025 On branch cf/5347 nothing to commit, working tree clean === applying patch ./v1-0001-Speedup-tuple-deformation-with-additional-functio.patch Applied patch to 'src/backend/executor/execTuples.c' with conflicts. U src/backend/executor/execTuples.c diff --cc src/backend/executor/execTuples.c index 7de490462d,afc43692be..0000000000 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@@ -999,9 -999,9 +999,10 @@@ tts_buffer_heap_store_tuple(TupleTableS * attribute that we're deforming. The caller can just call this * function with hasnulls set to constant-false and have the compiler * remove the constant-false branches and emit more optimal code. ++<<<<<<< ours * * Returns the next attnum to deform, which can be equal to natts when the - * function managed to deform all requested attributes. *offp is an input and + * function manages to deform all requested attributes. *offp is an input and * output parameter which is the byte offset within the tuple to start deforming * from which, on return, gets set to the offset where the next attribute * should be deformed from. *slowp is set to true when subsequent deforming @@@ -1030,78 -1030,77 +1031,247 @@@ slot_deform_heap_tuple_internal(TupleTa for (; attnum < natts; attnum++) { + CompactAttribute *thisatt = TupleDescCompactAttr(tupleDesc, attnum); + + if (hasnulls && att_isnull(attnum, bp)) + { + values[attnum] = (Datum) 0; + isnull[attnum] = true; + if (!slow) + { + *slowp = true; + return attnum + 1; + } + else + continue; + } + + isnull[attnum] = false; + + /* calculate the offset of this attribute */ + if (!slow && thisatt->attcacheoff >= 0) + *offp = thisatt->attcacheoff; + else if (thisatt->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute if the + * offset is already suitably aligned, so that there would be no + * pad bytes in any case: then the offset will be valid for either + * an aligned or unaligned value. + */ + if (!slow && *offp == att_nominal_alignby(*offp, thisatt->attalignby)) + thisatt->attcacheoff = *offp; + else + { + *offp = att_pointer_alignby(*offp, + thisatt->attalignby, + -1, + tp + *offp); + + if (!slow) + slownext = true; + } + } + else + { + /* not varlena, so safe to use att_nominal_alignby */ + *offp = att_nominal_alignby(*offp, thisatt->attalignby); + + if (!slow) + thisatt->attcacheoff = *offp; + } + + values[attnum] = fetchatt(thisatt, tp + *offp); + + *offp = att_addlength_pointer(*offp, thisatt->attlen, tp + *offp); + + /* check if we need to switch to slow mode */ + if (!slow) + { + /* + * We're unable to deform any further if the above code set + * 'slownext', or if this isn't a fixed-width attribute. + */ + if (slownext || thisatt->attlen <= 0) + { + *slowp = true; + return attnum + 1; + } + } + } + + return natts; +} + ++/* ++ * slot_deform_heap_tuple ++ * Given a TupleTableSlot, extract data from the slot's physical tuple ++ * into its Datum/isnull arrays. Data is extracted up through the ++ * natts'th column (caller must ensure this is a legal column number). ++======= ++>>>>>>> theirs ++ * ++ * Returns the next attnum to deform, which can be equal to natts when the ++ * function managed to deform all requested attributes. *offp is an input and ++ * output parameter which is the byte offset within the tuple to start deforming ++ * from which, on return, gets set to the offset where the next attribute ++ * should be deformed from. *slowp is set to true when subsequent deforming ++ * of this tuple must use a version of this function with "slow" passed as ++ * true. ++ * ++ * Callers cannot assume when we return "attnum" (i.e. all requested ++ * attributes have been deformed) that slow mode isn't required for any ++ * additional deforming as the final attribute may have caused a switch to ++ * slow mode. ++ */ ++static pg_attribute_always_inline int ++slot_deform_heap_tuple_internal(TupleTableSlot *slot, HeapTuple tuple, ++ int attnum, int natts, bool slow, ++ bool hasnulls, uint32 *offp, bool *slowp) ++{ ++<<<<<<< ours ++ bool hasnulls = HeapTupleHasNulls(tuple); ++ int attnum; ++ uint32 off; /* offset in tuple data */ ++ bool slow; /* can we use/set attcacheoff? */ ++ ++ /* We can only fetch as many attributes as the tuple has. */ ++ natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts); ++ ++ /* ++ * Check whether the first call for this tuple, and initialize or restore ++ * loop state. ++ */ ++ attnum = slot->tts_nvalid; ++ if (attnum == 0) ++ { ++ /* Start from the first attribute */ ++ off = 0; ++ slow = false; ++ } ++ else ++ { ++ /* Restore state from previous execution */ ++ off = *offp; ++ slow = TTS_SLOW(slot); ++ } ++======= ++ TupleDesc tupleDesc = slot->tts_tupleDescriptor; ++ Datum *values = slot->tts_values; ++ bool *isnull = slot->tts_isnull; ++ HeapTupleHeader tup = tuple->t_data; ++ char *tp; /* ptr to tuple data */ ++ bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ ++ bool slownext = false; ++>>>>>>> theirs ++ ++ /* ++ * If 'slow' isn't set, try deforming using deforming code that does not ++ * contain any of the extra checks required for non-fixed offset ++ * deforming. During deforming, if or when we find a NULL or a variable ++ * length attribute, we'll switch to a deforming method which includes the ++ * extra code required for non-fixed offset deforming, a.k.a slow mode. ++ * Because this is performance critical, we inline ++ * slot_deform_heap_tuple_internal passing the 'slow' and 'hasnull' ++ * parameters as constants to allow the compiler to emit specialized code ++ * with the known-const false comparisons and subsequent branches removed. ++ */ ++ if (!slow) ++ { ++<<<<<<< ours ++ /* Tuple without any NULLs? We can skip doing any NULL checking */ ++ if (!hasnulls) ++ attnum = slot_deform_heap_tuple_internal(slot, ++ tuple, ++ attnum, ++ natts, ++ false, /* slow */ ++ false, /* hasnulls */ ++ &off, ++ &slow); ++ else ++ attnum = slot_deform_heap_tuple_internal(slot, ++ tuple, ++ attnum, ++ natts, ++ false, /* slow */ ++ true, /* hasnulls */ ++ &off, ++ &slow); ++ } ++ ++======= + Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum); + + if (hasnulls && att_isnull(attnum, bp)) + { + values[attnum] = (Datum) 0; + isnull[attnum] = true; + if (!slow) + { + *slowp = true; + return attnum + 1; + } + else + continue; + } + + isnull[attnum] = false; + + /* calculate the offset of this attribute */ + if (!slow && thisatt->attcacheoff >= 0) + *offp = thisatt->attcacheoff; + else if (thisatt->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute if the + * offset is already suitably aligned, so that there would be no + * pad bytes in any case: then the offset will be valid for either + * an aligned or unaligned value. + */ + if (!slow && *offp == att_align_nominal(*offp, thisatt->attalign)) + thisatt->attcacheoff = *offp; + else + { + *offp = att_align_pointer(*offp, thisatt->attalign, -1, + tp + *offp); + + if (!slow) + slownext = true; + } + } + else + { + /* not varlena, so safe to use att_align_nominal */ + *offp = att_align_nominal(*offp, thisatt->attalign); + + if (!slow) + thisatt->attcacheoff = *offp; + } + + + values[attnum] = fetchatt(thisatt, tp + *offp); + + *offp = att_addlength_pointer(*offp, thisatt->attlen, tp + *offp); + + /* check if we need to switch to slow mode */ + if (!slow) + { + /* + * We're unable to deform any further if the above code set + * 'slownext', or if this isn't a fixed-width attribute. + */ + if (slownext || thisatt->attlen <= 0) + { + *slowp = true; + return attnum + 1; + } + } + } + + return natts; + } + /* * slot_deform_heap_tuple * Given a TupleTableSlot, extract data from the slot's physical tuple @@@ -1180,6 -1179,6 +1350,7 @@@ slot_deform_heap_tuple(TupleTableSlot * &slow); } ++>>>>>>> theirs /* If there's still work to do then we must be in slow mode */ if (attnum < natts) {