88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.200 2005/10/15 02:49:08 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.201 2005/11/20 18:38:20 tgl Exp $
1212 *
1313 *
1414 * INTERFACE ROUTINES
@@ -1085,12 +1085,19 @@ heap_get_latest_tid(Relation relation,
10851085 *
10861086 * use_fsm is passed directly to RelationGetBufferForTuple, which see for
10871087 * more info.
1088+ *
1089+ * The return value is the OID assigned to the tuple (either here or by the
1090+ * caller), or InvalidOid if no OID. The header fields of *tup are updated
1091+ * to match the stored tuple; in particular tup->t_self receives the actual
1092+ * TID where the tuple was stored. But note that any toasting of fields
1093+ * within the tuple data is NOT reflected into *tup.
10881094 */
10891095Oid
10901096heap_insert (Relation relation , HeapTuple tup , CommandId cid ,
10911097 bool use_wal , bool use_fsm )
10921098{
10931099 TransactionId xid = GetCurrentTransactionId ();
1100+ HeapTuple heaptup ;
10941101 Buffer buffer ;
10951102
10961103 if (relation -> rd_rel -> relhasoids )
@@ -1128,19 +1135,24 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
11281135 /*
11291136 * If the new tuple is too big for storage or contains already toasted
11301137 * out-of-line attributes from some other relation, invoke the toaster.
1138+ *
1139+ * Note: below this point, heaptup is the data we actually intend to
1140+ * store into the relation; tup is the caller's original untoasted data.
11311141 */
11321142 if (HeapTupleHasExternal (tup ) ||
11331143 (MAXALIGN (tup -> t_len ) > TOAST_TUPLE_THRESHOLD ))
1134- heap_tuple_toast_attrs (relation , tup , NULL );
1144+ heaptup = toast_insert_or_update (relation , tup , NULL );
1145+ else
1146+ heaptup = tup ;
11351147
11361148 /* Find buffer to insert this tuple into */
1137- buffer = RelationGetBufferForTuple (relation , tup -> t_len ,
1149+ buffer = RelationGetBufferForTuple (relation , heaptup -> t_len ,
11381150 InvalidBuffer , use_fsm );
11391151
11401152 /* NO EREPORT(ERROR) from here till changes are logged */
11411153 START_CRIT_SECTION ();
11421154
1143- RelationPutHeapTuple (relation , buffer , tup );
1155+ RelationPutHeapTuple (relation , buffer , heaptup );
11441156
11451157 /* XLOG stuff */
11461158 if (relation -> rd_istemp )
@@ -1158,15 +1170,15 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
11581170 uint8 info = XLOG_HEAP_INSERT ;
11591171
11601172 xlrec .target .node = relation -> rd_node ;
1161- xlrec .target .tid = tup -> t_self ;
1173+ xlrec .target .tid = heaptup -> t_self ;
11621174 rdata [0 ].data = (char * ) & xlrec ;
11631175 rdata [0 ].len = SizeOfHeapInsert ;
11641176 rdata [0 ].buffer = InvalidBuffer ;
11651177 rdata [0 ].next = & (rdata [1 ]);
11661178
1167- xlhdr .t_natts = tup -> t_data -> t_natts ;
1168- xlhdr .t_infomask = tup -> t_data -> t_infomask ;
1169- xlhdr .t_hoff = tup -> t_data -> t_hoff ;
1179+ xlhdr .t_natts = heaptup -> t_data -> t_natts ;
1180+ xlhdr .t_infomask = heaptup -> t_data -> t_infomask ;
1181+ xlhdr .t_hoff = heaptup -> t_data -> t_hoff ;
11701182
11711183 /*
11721184 * note we mark rdata[1] as belonging to buffer; if XLogInsert decides
@@ -1180,8 +1192,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
11801192 rdata [1 ].next = & (rdata [2 ]);
11811193
11821194 /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
1183- rdata [2 ].data = (char * ) tup -> t_data + offsetof(HeapTupleHeaderData , t_bits );
1184- rdata [2 ].len = tup -> t_len - offsetof(HeapTupleHeaderData , t_bits );
1195+ rdata [2 ].data = (char * ) heaptup -> t_data + offsetof(HeapTupleHeaderData , t_bits );
1196+ rdata [2 ].len = heaptup -> t_len - offsetof(HeapTupleHeaderData , t_bits );
11851197 rdata [2 ].buffer = buffer ;
11861198 rdata [2 ].buffer_std = true;
11871199 rdata [2 ].next = NULL ;
@@ -1191,7 +1203,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
11911203 * page instead of restoring the whole thing. Set flag, and hide
11921204 * buffer references from XLogInsert.
11931205 */
1194- if (ItemPointerGetOffsetNumber (& (tup -> t_self )) == FirstOffsetNumber &&
1206+ if (ItemPointerGetOffsetNumber (& (heaptup -> t_self )) == FirstOffsetNumber &&
11951207 PageGetMaxOffsetNumber (page ) == FirstOffsetNumber )
11961208 {
11971209 info |= XLOG_HEAP_INIT_PAGE ;
@@ -1212,13 +1224,23 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
12121224 /*
12131225 * If tuple is cachable, mark it for invalidation from the caches in case
12141226 * we abort. Note it is OK to do this after WriteBuffer releases the
1215- * buffer, because the "tup" data structure is all in local memory, not in
1216- * the shared buffer.
1227+ * buffer, because the heaptup data structure is all in local memory,
1228+ * not in the shared buffer.
12171229 */
1218- CacheInvalidateHeapTuple (relation , tup );
1230+ CacheInvalidateHeapTuple (relation , heaptup );
12191231
12201232 pgstat_count_heap_insert (& relation -> pgstat_info );
12211233
1234+ /*
1235+ * If heaptup is a private copy, release it. Don't forget to copy t_self
1236+ * back to the caller's image, too.
1237+ */
1238+ if (heaptup != tup )
1239+ {
1240+ tup -> t_self = heaptup -> t_self ;
1241+ heap_freetuple (heaptup );
1242+ }
1243+
12221244 return HeapTupleGetOid (tup );
12231245}
12241246
@@ -1469,7 +1491,7 @@ heap_delete(Relation relation, ItemPointer tid,
14691491 * context lock on the buffer first.
14701492 */
14711493 if (HeapTupleHasExternal (& tp ))
1472- heap_tuple_toast_attrs (relation , NULL , & tp );
1494+ toast_delete (relation , & tp );
14731495
14741496 /*
14751497 * Mark tuple for invalidation from system caches at next command
@@ -1553,8 +1575,10 @@ simple_heap_delete(Relation relation, ItemPointer tid)
15531575 * HeapTupleSelfUpdated, HeapTupleUpdated, or HeapTupleBeingUpdated
15541576 * (the last only possible if wait == false).
15551577 *
1556- * On success, newtup->t_self is set to the TID where the new tuple
1557- * was inserted.
1578+ * On success, the header fields of *newtup are updated to match the new
1579+ * stored tuple; in particular, newtup->t_self is set to the TID where the
1580+ * new tuple was inserted. However, any TOAST changes in the new tuple's
1581+ * data are not reflected into *newtup.
15581582 *
15591583 * In the failure cases, the routine returns the tuple's t_ctid and t_xmax.
15601584 * If t_ctid is the same as otid, the tuple was deleted; if different, the
@@ -1570,6 +1594,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
15701594 TransactionId xid = GetCurrentTransactionId ();
15711595 ItemId lp ;
15721596 HeapTupleData oldtup ;
1597+ HeapTuple heaptup ;
15731598 PageHeader dp ;
15741599 Buffer buffer ,
15751600 newbuf ;
@@ -1760,11 +1785,12 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
17601785 * We need to invoke the toaster if there are already any out-of-line toasted
17611786 * values present, or if the new tuple is over-threshold.
17621787 */
1788+ newtupsize = MAXALIGN (newtup -> t_len );
1789+
17631790 need_toast = (HeapTupleHasExternal (& oldtup ) ||
17641791 HeapTupleHasExternal (newtup ) ||
1765- ( MAXALIGN ( newtup -> t_len ) > TOAST_TUPLE_THRESHOLD ) );
1792+ newtupsize > TOAST_TUPLE_THRESHOLD );
17661793
1767- newtupsize = MAXALIGN (newtup -> t_len );
17681794 pagefree = PageGetFreeSpace ((Page ) dp );
17691795
17701796 if (need_toast || newtupsize > pagefree )
@@ -1776,15 +1802,25 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
17761802 HEAP_MOVED );
17771803 HeapTupleHeaderSetXmax (oldtup .t_data , xid );
17781804 HeapTupleHeaderSetCmax (oldtup .t_data , cid );
1805+ /* temporarily make it look not-updated */
1806+ oldtup .t_data -> t_ctid = oldtup .t_self ;
17791807 already_marked = true;
17801808 LockBuffer (buffer , BUFFER_LOCK_UNLOCK );
17811809
1782- /* Let the toaster do its thing */
1810+ /*
1811+ * Let the toaster do its thing, if needed.
1812+ *
1813+ * Note: below this point, heaptup is the data we actually intend to
1814+ * store into the relation; newtup is the caller's original untoasted
1815+ * data.
1816+ */
17831817 if (need_toast )
17841818 {
1785- heap_tuple_toast_attrs (relation , newtup , & oldtup );
1786- newtupsize = MAXALIGN (newtup -> t_len );
1819+ heaptup = toast_insert_or_update (relation , newtup , & oldtup );
1820+ newtupsize = MAXALIGN (heaptup -> t_len );
17871821 }
1822+ else
1823+ heaptup = newtup ;
17881824
17891825 /*
17901826 * Now, do we need a new page for the tuple, or not? This is a bit
@@ -1805,8 +1841,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
18051841 */
18061842 if (newtupsize > pagefree )
18071843 {
1808- /* Assume there's no chance to put newtup on same page. */
1809- newbuf = RelationGetBufferForTuple (relation , newtup -> t_len ,
1844+ /* Assume there's no chance to put heaptup on same page. */
1845+ newbuf = RelationGetBufferForTuple (relation , heaptup -> t_len ,
18101846 buffer , true);
18111847 }
18121848 else
@@ -1823,7 +1859,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
18231859 * seldom be taken.
18241860 */
18251861 LockBuffer (buffer , BUFFER_LOCK_UNLOCK );
1826- newbuf = RelationGetBufferForTuple (relation , newtup -> t_len ,
1862+ newbuf = RelationGetBufferForTuple (relation , heaptup -> t_len ,
18271863 buffer , true);
18281864 }
18291865 else
@@ -1838,6 +1874,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
18381874 /* No TOAST work needed, and it'll fit on same page */
18391875 already_marked = false;
18401876 newbuf = buffer ;
1877+ heaptup = newtup ;
18411878 }
18421879
18431880 /*
@@ -1849,7 +1886,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
18491886 /* NO EREPORT(ERROR) from here till changes are logged */
18501887 START_CRIT_SECTION ();
18511888
1852- RelationPutHeapTuple (relation , newbuf , newtup ); /* insert new tuple */
1889+ RelationPutHeapTuple (relation , newbuf , heaptup ); /* insert new tuple */
18531890
18541891 if (!already_marked )
18551892 {
@@ -1863,13 +1900,13 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
18631900 }
18641901
18651902 /* record address of new tuple in t_ctid of old one */
1866- oldtup .t_data -> t_ctid = newtup -> t_self ;
1903+ oldtup .t_data -> t_ctid = heaptup -> t_self ;
18671904
18681905 /* XLOG stuff */
18691906 if (!relation -> rd_istemp )
18701907 {
18711908 XLogRecPtr recptr = log_heap_update (relation , buffer , oldtup .t_self ,
1872- newbuf , newtup , false);
1909+ newbuf , heaptup , false);
18731910
18741911 if (newbuf != buffer )
18751912 {
@@ -1905,10 +1942,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
19051942 /*
19061943 * If new tuple is cachable, mark it for invalidation from the caches in
19071944 * case we abort. Note it is OK to do this after WriteBuffer releases the
1908- * buffer, because the "newtup" data structure is all in local memory, not
1945+ * buffer, because the heaptup data structure is all in local memory, not
19091946 * in the shared buffer.
19101947 */
1911- CacheInvalidateHeapTuple (relation , newtup );
1948+ CacheInvalidateHeapTuple (relation , heaptup );
19121949
19131950 /*
19141951 * Release the lmgr tuple lock, if we had it.
@@ -1918,6 +1955,16 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
19181955
19191956 pgstat_count_heap_update (& relation -> pgstat_info );
19201957
1958+ /*
1959+ * If heaptup is a private copy, release it. Don't forget to copy t_self
1960+ * back to the caller's image, too.
1961+ */
1962+ if (heaptup != newtup )
1963+ {
1964+ newtup -> t_self = heaptup -> t_self ;
1965+ heap_freetuple (heaptup );
1966+ }
1967+
19211968 return HeapTupleMayBeUpdated ;
19221969}
19231970
0 commit comments