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.
This commit is contained in:
parent
4f82112473
commit
2a6c032503
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.131 2004/12/31 21:59:41 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.132 2005/02/06 20:19:08 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -605,32 +605,80 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
|||||||
Relation NewHeap,
|
Relation NewHeap,
|
||||||
OldHeap,
|
OldHeap,
|
||||||
OldIndex;
|
OldIndex;
|
||||||
|
TupleDesc oldTupDesc;
|
||||||
|
TupleDesc newTupDesc;
|
||||||
|
int natts;
|
||||||
|
Datum *values;
|
||||||
|
char *nulls;
|
||||||
IndexScanDesc scan;
|
IndexScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the relations I need. Scan through the OldHeap on the OldIndex
|
* Open the relations we need.
|
||||||
* and insert each tuple into the NewHeap.
|
|
||||||
*/
|
*/
|
||||||
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
|
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
|
||||||
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
|
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
|
||||||
OldIndex = index_open(OIDOldIndex);
|
OldIndex = index_open(OIDOldIndex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Their tuple descriptors should be exactly alike, but here we only
|
||||||
|
* need assume that they have the same number of columns.
|
||||||
|
*/
|
||||||
|
oldTupDesc = RelationGetDescr(OldHeap);
|
||||||
|
newTupDesc = RelationGetDescr(NewHeap);
|
||||||
|
Assert(newTupDesc->natts == oldTupDesc->natts);
|
||||||
|
|
||||||
|
/* Preallocate values/nulls arrays */
|
||||||
|
natts = newTupDesc->natts;
|
||||||
|
values = (Datum *) palloc0(natts * sizeof(Datum));
|
||||||
|
nulls = (char *) palloc(natts * sizeof(char));
|
||||||
|
memset(nulls, 'n', natts * sizeof(char));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan through the OldHeap on the OldIndex and copy each tuple into the
|
||||||
|
* NewHeap.
|
||||||
|
*/
|
||||||
scan = index_beginscan(OldHeap, OldIndex, SnapshotNow, 0, (ScanKey) NULL);
|
scan = index_beginscan(OldHeap, OldIndex, SnapshotNow, 0, (ScanKey) NULL);
|
||||||
|
|
||||||
while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
|
while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We must copy the tuple because heap_insert() will overwrite the
|
* We cannot simply pass the tuple to heap_insert(), for several
|
||||||
* commit-status fields of the tuple it's handed, and the
|
* reasons:
|
||||||
* retrieved tuple will actually be in a disk buffer! Thus, the
|
|
||||||
* source relation would get trashed, which is bad news if we
|
|
||||||
* abort later on. (This was a bug in releases thru 7.0)
|
|
||||||
*
|
*
|
||||||
* Note that the copied tuple will have the original OID, if any, so
|
* 1. heap_insert() will overwrite the commit-status fields of the
|
||||||
* this does preserve OIDs.
|
* tuple it's handed. This would trash the source relation, which is
|
||||||
|
* bad news if we abort later on. (This was a bug in releases thru
|
||||||
|
* 7.0)
|
||||||
|
*
|
||||||
|
* 2. We'd like to squeeze out the values of any dropped columns,
|
||||||
|
* both to save space and to ensure we have no corner-case failures.
|
||||||
|
* (It's possible for example that the new table hasn't got a TOAST
|
||||||
|
* table and so is unable to store any large values of dropped cols.)
|
||||||
|
*
|
||||||
|
* 3. The tuple might not even be legal for the new table; this is
|
||||||
|
* currently only known to happen as an after-effect of ALTER TABLE
|
||||||
|
* SET WITHOUT OIDS.
|
||||||
|
*
|
||||||
|
* So, we must reconstruct the tuple from component Datums.
|
||||||
*/
|
*/
|
||||||
HeapTuple copiedTuple = heap_copytuple(tuple);
|
HeapTuple copiedTuple;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
heap_deformtuple(tuple, oldTupDesc, values, nulls);
|
||||||
|
|
||||||
|
/* Be sure to null out any dropped columns */
|
||||||
|
for (i = 0; i < natts; i++)
|
||||||
|
{
|
||||||
|
if (newTupDesc->attrs[i]->attisdropped)
|
||||||
|
nulls[i] = 'n';
|
||||||
|
}
|
||||||
|
|
||||||
|
copiedTuple = heap_formtuple(newTupDesc, values, nulls);
|
||||||
|
|
||||||
|
/* Preserve OID, if any */
|
||||||
|
if (NewHeap->rd_rel->relhasoids)
|
||||||
|
HeapTupleSetOid(copiedTuple, HeapTupleGetOid(tuple));
|
||||||
|
|
||||||
simple_heap_insert(NewHeap, copiedTuple);
|
simple_heap_insert(NewHeap, copiedTuple);
|
||||||
|
|
||||||
@ -641,6 +689,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
|||||||
|
|
||||||
index_endscan(scan);
|
index_endscan(scan);
|
||||||
|
|
||||||
|
pfree(values);
|
||||||
|
pfree(nulls);
|
||||||
|
|
||||||
index_close(OldIndex);
|
index_close(OldIndex);
|
||||||
heap_close(OldHeap, NoLock);
|
heap_close(OldHeap, NoLock);
|
||||||
heap_close(NewHeap, NoLock);
|
heap_close(NewHeap, NoLock);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user