Skip to content

Commit 89eafad

Browse files
committed
Fix tuple deforming with virtual generated columns
TupleDescFinalize() failed to take into account virtual generated columns, which are always stored as NULL in tuples. TupleDescFinalize() didn't check for this, and that could result in attcacheoff being set for and beyond virtual generated columns. Also, the TupleDesc's firstNonGuaranteedAttr could also be set incorrectly, which could result in the tuple deformation function deforming without checking for NULLs, and deforming using incorrectly cached offsets. This could result in tuples being deformed incorrectly, which could result in incorrect results, ERRORs or possibly a crash. This has been broken since c456e39. Author: Chao Li <li.evan.chao@gmail.com> Reported-by: Chao Li <li.evan.chao@gmail.com> Reviewed-by: ChangAo Chen <cca5507@qq.com> Reviewed-by: David Rowley <dgrowleyml@gmail.com> Discussion: https://postgr.es/m/A4BC563C-0CA3-4EF3-952A-EA41F9E5BF1E%40gmail.com
1 parent 193a4de commit 89eafad

2 files changed

Lines changed: 18 additions & 2 deletions

File tree

src/backend/access/common/tupdesc.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ TupleDescFinalize(TupleDesc tupdesc)
517517
for (int i = 0; i < tupdesc->natts; i++)
518518
{
519519
CompactAttribute *cattr = TupleDescCompactAttr(tupdesc, i);
520+
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
520521

521522
/*
522523
* Find the highest attnum which is guaranteed to exist in all tuples
@@ -525,10 +526,18 @@ TupleDescFinalize(TupleDesc tupdesc)
525526
*/
526527
if (firstNonGuaranteedAttr == tupdesc->natts &&
527528
(cattr->attnullability != ATTNULLABLE_VALID || !cattr->attbyval ||
528-
cattr->atthasmissing || cattr->attisdropped || cattr->attlen <= 0))
529+
cattr->atthasmissing || cattr->attisdropped ||
530+
cattr->attlen <= 0 ||
531+
attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL))
529532
firstNonGuaranteedAttr = i;
530533

531-
if (cattr->attlen <= 0)
534+
/*
535+
* Don't cache offsets beyond fixed-width attributes. Virtual
536+
* generated attributes are stored as NULLs in the tuple, so we don't
537+
* cache offsets beyond these.
538+
*/
539+
if (cattr->attlen <= 0 ||
540+
attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
532541
break;
533542

534543
off = att_nominal_alignby(off, cattr->attalignby);

src/backend/executor/execTuples.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,13 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
10741074
{
10751075
/* Otherwise all required columns are guaranteed to exist */
10761076
firstNullAttr = natts;
1077+
1078+
/*
1079+
* Check TupleDescFinalize() didn't get confused when setting
1080+
* firstNonGuaranteedAttr. There should never be a NULL in a
1081+
* guaranteed column.
1082+
*/
1083+
Assert(first_null_attr(tup->t_bits, natts) >= firstNullAttr);
10771084
}
10781085
}
10791086
else

0 commit comments

Comments
 (0)