=== Applying patches on top of PostgreSQL commit ID 323530e00d279f267265ef32c7e6b40a04c94105 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Fri Jul 17 03:11:28 UTC 2026 On branch cf/5879 nothing to commit, working tree clean === using 'git am' to apply patch ./v2026-01-12-v2-0001-Move-normalize-tuple-logic-from-nbtch.patch === Applying: Move `normalize tuple` logic from nbtcheck to verify_common Using index info to reconstruct a base tree... M contrib/amcheck/verify_common.c M contrib/amcheck/verify_nbtree.c Falling back to patching base and 3-way merge... Auto-merging contrib/amcheck/verify_nbtree.c CONFLICT (content): Merge conflict in contrib/amcheck/verify_nbtree.c Auto-merging contrib/amcheck/verify_common.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Move `normalize tuple` logic from nbtcheck to verify_common When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v2026-01-12-v2-0001-Move-normalize-tuple-logic-from-nbtch.patch === patching file contrib/amcheck/verify_common.c patching file contrib/amcheck/verify_common.h patching file contrib/amcheck/verify_nbtree.c Hunk #2 FAILED at 2844. 1 out of 2 hunks FAILED -- saving rejects to file contrib/amcheck/verify_nbtree.c.rej Unstaged changes after reset: M contrib/amcheck/verify_common.c M contrib/amcheck/verify_common.h M contrib/amcheck/verify_nbtree.c Removing contrib/amcheck/verify_nbtree.c.rej === using 'git apply' to apply patch ./v2026-01-12-v2-0001-Move-normalize-tuple-logic-from-nbtch.patch === Applied patch to 'contrib/amcheck/verify_common.c' cleanly. Applied patch to 'contrib/amcheck/verify_common.h' cleanly. Applied patch to 'contrib/amcheck/verify_nbtree.c' with conflicts. U contrib/amcheck/verify_nbtree.c diff --cc contrib/amcheck/verify_nbtree.c index 3ef2d66f826,426e23d2960..00000000000 --- a/contrib/amcheck/verify_nbtree.c +++ b/contrib/amcheck/verify_nbtree.c @@@ -2852,112 -2847,7 +2851,108 @@@ bt_normalize_tuple(BtreeCheckState *sta /* Caller should only pass "logical" non-pivot tuples here */ Assert(!BTreeTupleIsPosting(itup) && !BTreeTupleIsPivot(itup)); ++<<<<<<< ours + /* Easy case: It's immediately clear that tuple has no varlena datums */ + if (!IndexTupleHasVarwidths(itup)) + return itup; + + for (i = 0; i < tupleDescriptor->natts; i++) + { + Form_pg_attribute att; + + att = TupleDescAttr(tupleDescriptor, i); + + /* Assume untoasted/already normalized datum initially */ + need_free[i] = false; + normalized[i] = index_getattr(itup, att->attnum, + tupleDescriptor, + &isnull[i]); + if (att->attbyval || att->attlen != -1 || isnull[i]) + continue; + + /* + * Callers always pass a tuple that could safely be inserted into the + * index without further processing, so an external varlena header + * should never be encountered here + */ + if (VARATT_IS_EXTERNAL(DatumGetPointer(normalized[i]))) + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("external varlena datum in tuple that references heap row (%u,%u) in index \"%s\"", + ItemPointerGetBlockNumber(&(itup->t_tid)), + ItemPointerGetOffsetNumber(&(itup->t_tid)), + RelationGetRelationName(state->rel)))); + else if (!VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i])) && + VARSIZE_ANY(DatumGetPointer(normalized[i])) > TOAST_INDEX_TARGET && + (att->attstorage == TYPSTORAGE_EXTENDED || + att->attstorage == TYPSTORAGE_MAIN)) + { + /* + * This value will be compressed by index_form_tuple() with the + * current storage settings. We may be here because this tuple + * was formed with different storage settings. So, force forming. + */ + formnewtup = true; + } + else if (VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i]))) + { + formnewtup = true; + normalized[i] = PointerGetDatum(PG_DETOAST_DATUM(normalized[i])); + need_free[i] = true; + } + + /* + * Short tuples may have 1B or 4B header. Convert 4B header of short + * tuples to 1B + */ + else if (VARATT_CAN_MAKE_SHORT(DatumGetPointer(normalized[i]))) + { + /* convert to short varlena */ + Size len = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(normalized[i])); + char *data = palloc(len); + + SET_VARSIZE_SHORT(data, len); + memcpy(data + 1, VARDATA(DatumGetPointer(normalized[i])), len - 1); + + formnewtup = true; + normalized[i] = PointerGetDatum(data); + need_free[i] = true; + } + } + + /* + * Easier case: Tuple has varlena datums, none of which are compressed or + * short with 4B header + */ + if (!formnewtup) + return itup; + + /* + * Hard case: Tuple had compressed varlena datums that necessitate + * creating normalized version of the tuple from uncompressed input datums + * (normalized input datums). This is rather naive, but shouldn't be + * necessary too often. + * + * In the heap, tuples may contain short varlena datums with both 1B + * header and 4B headers. But the corresponding index tuple should always + * have such varlena's with 1B headers. So, if there is a short varlena + * with 4B header, we need to convert it for fingerprinting. + * + * Note that we rely on deterministic index_form_tuple() TOAST compression + * of normalized input. + */ + reformed = index_form_tuple(tupleDescriptor, normalized, isnull); + reformed->t_tid = itup->t_tid; + + /* Cannot leak memory here */ + for (i = 0; i < tupleDescriptor->natts; i++) + if (need_free[i]) + pfree(DatumGetPointer(normalized[i])); + + return reformed; ++======= + return amcheck_normalize_tuple(state->rel, itup); ++>>>>>>> theirs } /*