88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.41 2003/11/29 19:51:40 pgsql Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.42 2004/06/04 20:35:21 tgl Exp $
1212 *
1313 *
1414 * INTERFACE ROUTINES
@@ -281,15 +281,26 @@ toast_delete(Relation rel, HeapTuple oldtup)
281281 Form_pg_attribute * att ;
282282 int numAttrs ;
283283 int i ;
284- Datum value ;
285- bool isnull ;
284+ Datum toast_values [ MaxHeapAttributeNumber ] ;
285+ char toast_nulls [ MaxHeapAttributeNumber ] ;
286286
287287 /*
288- * Get the tuple descriptor, the number of and attribute descriptors.
288+ * Get the tuple descriptor and break down the tuple into fields.
289+ *
290+ * NOTE: it's debatable whether to use heap_deformtuple() here or
291+ * just heap_getattr() only the varlena columns. The latter could
292+ * win if there are few varlena columns and many non-varlena ones.
293+ * However, heap_deformtuple costs only O(N) while the heap_getattr
294+ * way would cost O(N^2) if there are many varlena columns, so it
295+ * seems better to err on the side of linear cost. (We won't even
296+ * be here unless there's at least one varlena column, by the way.)
289297 */
290298 tupleDesc = rel -> rd_att ;
291- numAttrs = tupleDesc -> natts ;
292299 att = tupleDesc -> attrs ;
300+ numAttrs = tupleDesc -> natts ;
301+
302+ Assert (numAttrs <= MaxHeapAttributeNumber );
303+ heap_deformtuple (oldtup , tupleDesc , toast_values , toast_nulls );
293304
294305 /*
295306 * Check for external stored attributes and delete them from the
@@ -299,8 +310,9 @@ toast_delete(Relation rel, HeapTuple oldtup)
299310 {
300311 if (att [i ]-> attlen == -1 )
301312 {
302- value = heap_getattr (oldtup , i + 1 , tupleDesc , & isnull );
303- if (!isnull && VARATT_IS_EXTERNAL (value ))
313+ Datum value = toast_values [i ];
314+
315+ if (toast_nulls [i ] != 'n' && VARATT_IS_EXTERNAL (value ))
304316 toast_delete_datum (rel , value );
305317 }
306318 }
@@ -321,8 +333,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
321333 Form_pg_attribute * att ;
322334 int numAttrs ;
323335 int i ;
324- bool old_isnull ;
325- bool new_isnull ;
326336
327337 bool need_change = false;
328338 bool need_free = false;
@@ -333,18 +343,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
333343
334344 char toast_action [MaxHeapAttributeNumber ];
335345 char toast_nulls [MaxHeapAttributeNumber ];
346+ char toast_oldnulls [MaxHeapAttributeNumber ];
336347 Datum toast_values [MaxHeapAttributeNumber ];
348+ Datum toast_oldvalues [MaxHeapAttributeNumber ];
337349 int32 toast_sizes [MaxHeapAttributeNumber ];
338350 bool toast_free [MaxHeapAttributeNumber ];
339351 bool toast_delold [MaxHeapAttributeNumber ];
340352
341353 /*
342- * Get the tuple descriptor, the number of and attribute descriptors
343- * and the location of the tuple values.
354+ * Get the tuple descriptor and break down the tuple(s) into fields.
344355 */
345356 tupleDesc = rel -> rd_att ;
346- numAttrs = tupleDesc -> natts ;
347357 att = tupleDesc -> attrs ;
358+ numAttrs = tupleDesc -> natts ;
359+
360+ Assert (numAttrs <= MaxHeapAttributeNumber );
361+ heap_deformtuple (newtup , tupleDesc , toast_values , toast_nulls );
362+ if (oldtup != NULL )
363+ heap_deformtuple (oldtup , tupleDesc , toast_oldvalues , toast_oldnulls );
348364
349365 /* ----------
350366 * Then collect information about the values given
@@ -353,12 +369,15 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
353369 * ' ' default handling
354370 * 'p' already processed --- don't touch it
355371 * 'x' incompressible, but OK to move off
372+ *
373+ * NOTE: toast_sizes[i] is only made valid for varlena attributes with
374+ * toast_action[i] different from 'p'.
356375 * ----------
357376 */
358377 memset (toast_action , ' ' , numAttrs * sizeof (char ));
359- memset (toast_nulls , ' ' , numAttrs * sizeof (char ));
360378 memset (toast_free , 0 , numAttrs * sizeof (bool ));
361379 memset (toast_delold , 0 , numAttrs * sizeof (bool ));
380+
362381 for (i = 0 ; i < numAttrs ; i ++ )
363382 {
364383 varattrib * old_value ;
@@ -369,27 +388,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
369388 /*
370389 * For UPDATE get the old and new values of this attribute
371390 */
372- old_value = (varattrib * ) DatumGetPointer (
373- heap_getattr (oldtup , i + 1 , tupleDesc , & old_isnull ));
374- toast_values [i ] =
375- heap_getattr (newtup , i + 1 , tupleDesc , & new_isnull );
391+ old_value = (varattrib * ) DatumGetPointer (toast_oldvalues [i ]);
376392 new_value = (varattrib * ) DatumGetPointer (toast_values [i ]);
377393
378394 /*
379395 * If the old value is an external stored one, check if it has
380396 * changed so we have to delete it later.
381397 */
382- if (! old_isnull && att [i ]-> attlen == -1 &&
398+ if (att [i ]-> attlen == -1 && toast_oldnulls [ i ] != 'n' &&
383399 VARATT_IS_EXTERNAL (old_value ))
384400 {
385- if (new_isnull || !VARATT_IS_EXTERNAL (new_value ) ||
401+ if (toast_nulls [ i ] == 'n' || !VARATT_IS_EXTERNAL (new_value ) ||
386402 old_value -> va_content .va_external .va_valueid !=
387403 new_value -> va_content .va_external .va_valueid ||
388404 old_value -> va_content .va_external .va_toastrelid !=
389405 new_value -> va_content .va_external .va_toastrelid )
390406 {
391407 /*
392- * The old external store value isn't needed any more
408+ * The old external stored value isn't needed any more
393409 * after the update
394410 */
395411 toast_delold [i ] = true;
@@ -413,23 +429,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
413429 /*
414430 * For INSERT simply get the new value
415431 */
416- toast_values [i ] =
417- heap_getattr (newtup , i + 1 , tupleDesc , & new_isnull );
432+ new_value = (varattrib * ) DatumGetPointer (toast_values [i ]);
418433 }
419434
420435 /*
421436 * Handle NULL attributes
422437 */
423- if (new_isnull )
438+ if (toast_nulls [ i ] == 'n' )
424439 {
425440 toast_action [i ] = 'p' ;
426- toast_nulls [i ] = 'n' ;
427441 has_nulls = true;
428442 continue ;
429443 }
430444
431445 /*
432- * Now look at varsize attributes
446+ * Now look at varlena attributes
433447 */
434448 if (att [i ]-> attlen == -1 )
435449 {
@@ -461,10 +475,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
461475 else
462476 {
463477 /*
464- * Not a variable size attribute, plain storage always
478+ * Not a varlena attribute, plain storage always
465479 */
466480 toast_action [i ] = 'p' ;
467- toast_sizes [i ] = att [i ]-> attlen ;
468481 }
469482 }
470483
@@ -768,8 +781,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
768781 if (need_delold )
769782 for (i = 0 ; i < numAttrs ; i ++ )
770783 if (toast_delold [i ])
771- toast_delete_datum (rel ,
772- heap_getattr (oldtup , i + 1 , tupleDesc , & old_isnull ));
784+ toast_delete_datum (rel , toast_oldvalues [i ]);
773785}
774786
775787
0 commit comments