Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2a6c032

Browse files
committed
Repair CLUSTER failure after ALTER TABLE SET WITHOUT OIDS. Turns out
there are corner cases involving dropping toasted columns in which the previous coding would fail, too: the new version of the table might not have any TOAST table, but we'd still propagate possibly-wide values of dropped columns forward.
1 parent 4f82112 commit 2a6c032

File tree

1 file changed

+62
-11
lines changed

1 file changed

+62
-11
lines changed

src/backend/commands/cluster.c

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.131 2004/12/31 21:59:41 pgsql Exp $
14+
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.132 2005/02/06 20:19:08 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -605,32 +605,80 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
605605
Relation NewHeap,
606606
OldHeap,
607607
OldIndex;
608+
TupleDesc oldTupDesc;
609+
TupleDesc newTupDesc;
610+
int natts;
611+
Datum *values;
612+
char *nulls;
608613
IndexScanDesc scan;
609614
HeapTuple tuple;
610615

611616
/*
612-
* Open the relations I need. Scan through the OldHeap on the OldIndex
613-
* and insert each tuple into the NewHeap.
617+
* Open the relations we need.
614618
*/
615619
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
616620
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
617621
OldIndex = index_open(OIDOldIndex);
618622

623+
/*
624+
* Their tuple descriptors should be exactly alike, but here we only
625+
* need assume that they have the same number of columns.
626+
*/
627+
oldTupDesc = RelationGetDescr(OldHeap);
628+
newTupDesc = RelationGetDescr(NewHeap);
629+
Assert(newTupDesc->natts == oldTupDesc->natts);
630+
631+
/* Preallocate values/nulls arrays */
632+
natts = newTupDesc->natts;
633+
values = (Datum *) palloc0(natts * sizeof(Datum));
634+
nulls = (char *) palloc(natts * sizeof(char));
635+
memset(nulls, 'n', natts * sizeof(char));
636+
637+
/*
638+
* Scan through the OldHeap on the OldIndex and copy each tuple into the
639+
* NewHeap.
640+
*/
619641
scan = index_beginscan(OldHeap, OldIndex, SnapshotNow, 0, (ScanKey) NULL);
620642

621643
while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
622644
{
623645
/*
624-
* We must copy the tuple because heap_insert() will overwrite the
625-
* commit-status fields of the tuple it's handed, and the
626-
* retrieved tuple will actually be in a disk buffer! Thus, the
627-
* source relation would get trashed, which is bad news if we
628-
* abort later on. (This was a bug in releases thru 7.0)
646+
* We cannot simply pass the tuple to heap_insert(), for several
647+
* reasons:
648+
*
649+
* 1. heap_insert() will overwrite the commit-status fields of the
650+
* tuple it's handed. This would trash the source relation, which is
651+
* bad news if we abort later on. (This was a bug in releases thru
652+
* 7.0)
653+
*
654+
* 2. We'd like to squeeze out the values of any dropped columns,
655+
* both to save space and to ensure we have no corner-case failures.
656+
* (It's possible for example that the new table hasn't got a TOAST
657+
* table and so is unable to store any large values of dropped cols.)
629658
*
630-
* Note that the copied tuple will have the original OID, if any, so
631-
* this does preserve OIDs.
659+
* 3. The tuple might not even be legal for the new table; this is
660+
* currently only known to happen as an after-effect of ALTER TABLE
661+
* SET WITHOUT OIDS.
662+
*
663+
* So, we must reconstruct the tuple from component Datums.
632664
*/
633-
HeapTuple copiedTuple = heap_copytuple(tuple);
665+
HeapTuple copiedTuple;
666+
int i;
667+
668+
heap_deformtuple(tuple, oldTupDesc, values, nulls);
669+
670+
/* Be sure to null out any dropped columns */
671+
for (i = 0; i < natts; i++)
672+
{
673+
if (newTupDesc->attrs[i]->attisdropped)
674+
nulls[i] = 'n';
675+
}
676+
677+
copiedTuple = heap_formtuple(newTupDesc, values, nulls);
678+
679+
/* Preserve OID, if any */
680+
if (NewHeap->rd_rel->relhasoids)
681+
HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
634682

635683
simple_heap_insert(NewHeap, copiedTuple);
636684

@@ -641,6 +689,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
641689

642690
index_endscan(scan);
643691

692+
pfree(values);
693+
pfree(nulls);
694+
644695
index_close(OldIndex);
645696
heap_close(OldHeap, NoLock);
646697
heap_close(NewHeap, NoLock);

0 commit comments

Comments
 (0)