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)
605605Relation NewHeap ,
606606OldHeap ,
607607OldIndex ;
608+ TupleDesc oldTupDesc ;
609+ TupleDesc newTupDesc ;
610+ int natts ;
611+ Datum * values ;
612+ char * nulls ;
608613IndexScanDesc scan ;
609614HeapTuple 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 */
615619NewHeap = heap_open (OIDNewHeap ,AccessExclusiveLock );
616620OldHeap = heap_open (OIDOldHeap ,AccessExclusiveLock );
617621OldIndex = 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+ */
619641scan = index_beginscan (OldHeap ,OldIndex ,SnapshotNow ,0 , (ScanKey )NULL );
620642
621643while ((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
635683simple_heap_insert (NewHeap ,copiedTuple );
636684
@@ -641,6 +689,9 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
641689
642690index_endscan (scan );
643691
692+ pfree (values );
693+ pfree (nulls );
694+
644695index_close (OldIndex );
645696heap_close (OldHeap ,NoLock );
646697heap_close (NewHeap ,NoLock );