2525
2626static struct varlena * toast_fetch_datum (struct varlena * attr );
2727static struct varlena * toast_fetch_datum_slice (struct varlena * attr ,
28- int32 sliceoffset , int32 length );
28+ int32 sliceoffset ,
29+ int32 slicelength );
2930static struct varlena * toast_decompress_datum (struct varlena * attr );
3031static struct varlena * toast_decompress_datum_slice (struct varlena * attr , int32 slicelength );
3132
@@ -331,14 +332,9 @@ toast_fetch_datum(struct varlena *attr)
331332 TupleDesc toasttupDesc ;
332333 struct varlena * result ;
333334 struct varatt_external toast_pointer ;
334- int32 ressize ;
335- int32 residx ,
336- nextidx ;
337- int32 numchunks ;
338- Pointer chunk ;
339- bool isnull ;
340- char * chunkdata ;
341- int32 chunksize ;
335+ int32 attrsize ;
336+ int32 expectedchunk ;
337+ int32 totalchunks ;
342338 int num_indexes ;
343339 int validIndex ;
344340 SnapshotData SnapshotToast ;
@@ -349,15 +345,15 @@ toast_fetch_datum(struct varlena *attr)
349345 /* Must copy to access aligned fields */
350346 VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
351347
352- ressize = toast_pointer .va_extsize ;
353- numchunks = ((ressize - 1 ) / TOAST_MAX_CHUNK_SIZE ) + 1 ;
348+ attrsize = toast_pointer .va_extsize ;
349+ totalchunks = ((attrsize - 1 ) / TOAST_MAX_CHUNK_SIZE ) + 1 ;
354350
355- result = (struct varlena * ) palloc (ressize + VARHDRSZ );
351+ result = (struct varlena * ) palloc (attrsize + VARHDRSZ );
356352
357353 if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ))
358- SET_VARSIZE_COMPRESSED (result , ressize + VARHDRSZ );
354+ SET_VARSIZE_COMPRESSED (result , attrsize + VARHDRSZ );
359355 else
360- SET_VARSIZE (result , ressize + VARHDRSZ );
356+ SET_VARSIZE (result , attrsize + VARHDRSZ );
361357
362358 /*
363359 * Open the toast relation and its indexes
@@ -386,17 +382,24 @@ toast_fetch_datum(struct varlena *attr)
386382 * see the chunks in chunkidx order, even though we didn't explicitly ask
387383 * for it.
388384 */
389- nextidx = 0 ;
385+ expectedchunk = 0 ;
390386
391387 init_toast_snapshot (& SnapshotToast );
392388 toastscan = systable_beginscan_ordered (toastrel , toastidxs [validIndex ],
393389 & SnapshotToast , 1 , & toastkey );
394390 while ((ttup = systable_getnext_ordered (toastscan , ForwardScanDirection )) != NULL )
395391 {
392+ int32 curchunk ;
393+ Pointer chunk ;
394+ bool isnull ;
395+ char * chunkdata ;
396+ int32 chunksize ;
397+ int32 expected_size ;
398+
396399 /*
397400 * Have a chunk, extract the sequence number and the data
398401 */
399- residx = DatumGetInt32 (fastgetattr (ttup , 2 , toasttupDesc , & isnull ));
402+ curchunk = DatumGetInt32 (fastgetattr (ttup , 2 , toasttupDesc , & isnull ));
400403 Assert (!isnull );
401404 chunk = DatumGetPointer (fastgetattr (ttup , 3 , toasttupDesc , & isnull ));
402405 Assert (!isnull );
@@ -424,63 +427,50 @@ toast_fetch_datum(struct varlena *attr)
424427 /*
425428 * Some checks on the data we've found
426429 */
427- if (residx != nextidx )
430+ if (curchunk != expectedchunk )
428431 ereport (ERROR ,
429432 (errcode (ERRCODE_DATA_CORRUPTED ),
430433 errmsg_internal ("unexpected chunk number %d (expected %d) for toast value %u in %s" ,
431- residx , nextidx ,
434+ curchunk , expectedchunk ,
432435 toast_pointer .va_valueid ,
433436 RelationGetRelationName (toastrel ))));
434- if (residx < numchunks - 1 )
435- {
436- if (chunksize != TOAST_MAX_CHUNK_SIZE )
437- ereport (ERROR ,
438- (errcode (ERRCODE_DATA_CORRUPTED ),
439- errmsg_internal ("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s" ,
440- chunksize , (int ) TOAST_MAX_CHUNK_SIZE ,
441- residx , numchunks ,
442- toast_pointer .va_valueid ,
443- RelationGetRelationName (toastrel ))));
444- }
445- else if (residx == numchunks - 1 )
446- {
447- if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize ) != ressize )
448- ereport (ERROR ,
449- (errcode (ERRCODE_DATA_CORRUPTED ),
450- errmsg_internal ("unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s" ,
451- chunksize ,
452- (int ) (ressize - residx * TOAST_MAX_CHUNK_SIZE ),
453- residx ,
454- toast_pointer .va_valueid ,
455- RelationGetRelationName (toastrel ))));
456- }
457- else
437+ if (curchunk > totalchunks - 1 )
458438 ereport (ERROR ,
459439 (errcode (ERRCODE_DATA_CORRUPTED ),
460440 errmsg_internal ("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s" ,
461- residx ,
462- 0 , numchunks - 1 ,
441+ curchunk ,
442+ 0 , totalchunks - 1 ,
443+ toast_pointer .va_valueid ,
444+ RelationGetRelationName (toastrel ))));
445+ expected_size = curchunk < totalchunks - 1 ? TOAST_MAX_CHUNK_SIZE
446+ : attrsize % TOAST_MAX_CHUNK_SIZE ;
447+ if (chunksize != expected_size )
448+ ereport (ERROR ,
449+ (errcode (ERRCODE_DATA_CORRUPTED ),
450+ errmsg_internal ("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s" ,
451+ chunksize , expected_size ,
452+ curchunk , totalchunks ,
463453 toast_pointer .va_valueid ,
464454 RelationGetRelationName (toastrel ))));
465455
466456 /*
467457 * Copy the data into proper place in our result
468458 */
469- memcpy (VARDATA (result ) + residx * TOAST_MAX_CHUNK_SIZE ,
459+ memcpy (VARDATA (result ) + curchunk * TOAST_MAX_CHUNK_SIZE ,
470460 chunkdata ,
471461 chunksize );
472462
473- nextidx ++ ;
463+ expectedchunk ++ ;
474464 }
475465
476466 /*
477467 * Final checks that we successfully fetched the datum
478468 */
479- if (nextidx != numchunks )
469+ if (expectedchunk != totalchunks )
480470 ereport (ERROR ,
481471 (errcode (ERRCODE_DATA_CORRUPTED ),
482472 errmsg_internal ("missing chunk number %d for toast value %u in %s" ,
483- nextidx ,
473+ expectedchunk ,
484474 toast_pointer .va_valueid ,
485475 RelationGetRelationName (toastrel ))));
486476
@@ -506,7 +496,8 @@ toast_fetch_datum(struct varlena *attr)
506496 * ----------
507497 */
508498static struct varlena *
509- toast_fetch_datum_slice (struct varlena * attr , int32 sliceoffset , int32 length )
499+ toast_fetch_datum_slice (struct varlena * attr , int32 sliceoffset ,
500+ int32 slicelength )
510501{
511502 Relation toastrel ;
512503 Relation * toastidxs ;
@@ -518,20 +509,10 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
518509 struct varlena * result ;
519510 struct varatt_external toast_pointer ;
520511 int32 attrsize ;
521- int32 residx ;
522- int32 nextidx ;
523- int numchunks ;
512+ int32 expectedchunk ;
524513 int startchunk ;
525514 int endchunk ;
526- int32 startoffset ;
527- int32 endoffset ;
528515 int totalchunks ;
529- Pointer chunk ;
530- bool isnull ;
531- char * chunkdata ;
532- int32 chunksize ;
533- int32 chcpystrt ;
534- int32 chcpyend ;
535516 int num_indexes ;
536517 int validIndex ;
537518 SnapshotData SnapshotToast ;
@@ -555,36 +536,33 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
555536 if (sliceoffset >= attrsize )
556537 {
557538 sliceoffset = 0 ;
558- length = 0 ;
539+ slicelength = 0 ;
559540 }
560541
561542 /*
562543 * When fetching a prefix of a compressed external datum, account for the
563544 * rawsize tracking amount of raw data, which is stored at the beginning
564545 * as an int32 value).
565546 */
566- if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ) && length > 0 )
567- length = length + sizeof (int32 );
547+ if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ) && slicelength > 0 )
548+ slicelength = slicelength + sizeof (int32 );
568549
569- if (((sliceoffset + length ) > attrsize ) || length < 0 )
570- length = attrsize - sliceoffset ;
550+ if (((sliceoffset + slicelength ) > attrsize ) || slicelength < 0 )
551+ slicelength = attrsize - sliceoffset ;
571552
572- result = (struct varlena * ) palloc (length + VARHDRSZ );
553+ result = (struct varlena * ) palloc (slicelength + VARHDRSZ );
573554
574555 if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ))
575- SET_VARSIZE_COMPRESSED (result , length + VARHDRSZ );
556+ SET_VARSIZE_COMPRESSED (result , slicelength + VARHDRSZ );
576557 else
577- SET_VARSIZE (result , length + VARHDRSZ );
558+ SET_VARSIZE (result , slicelength + VARHDRSZ );
578559
579- if (length == 0 )
560+ if (slicelength == 0 )
580561 return result ; /* Can save a lot of work at this point! */
581562
582563 startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE ;
583- endchunk = (sliceoffset + length - 1 ) / TOAST_MAX_CHUNK_SIZE ;
584- numchunks = (endchunk - startchunk ) + 1 ;
585-
586- startoffset = sliceoffset % TOAST_MAX_CHUNK_SIZE ;
587- endoffset = (sliceoffset + length - 1 ) % TOAST_MAX_CHUNK_SIZE ;
564+ endchunk = (sliceoffset + slicelength - 1 ) / TOAST_MAX_CHUNK_SIZE ;
565+ Assert (endchunk < totalchunks );
588566
589567 /*
590568 * Open the toast relation and its indexes
@@ -610,7 +588,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
610588 /*
611589 * Use equality condition for one chunk, a range condition otherwise:
612590 */
613- if (numchunks == 1 )
591+ if (startchunk == endchunk )
614592 {
615593 ScanKeyInit (& toastkey [1 ],
616594 (AttrNumber ) 2 ,
@@ -637,15 +615,24 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
637615 * The index is on (valueid, chunkidx) so they will come in order
638616 */
639617 init_toast_snapshot (& SnapshotToast );
640- nextidx = startchunk ;
618+ expectedchunk = startchunk ;
641619 toastscan = systable_beginscan_ordered (toastrel , toastidxs [validIndex ],
642620 & SnapshotToast , nscankeys , toastkey );
643621 while ((ttup = systable_getnext_ordered (toastscan , ForwardScanDirection )) != NULL )
644622 {
623+ int32 curchunk ;
624+ Pointer chunk ;
625+ bool isnull ;
626+ char * chunkdata ;
627+ int32 chunksize ;
628+ int32 expected_size ;
629+ int32 chcpystrt ;
630+ int32 chcpyend ;
631+
645632 /*
646633 * Have a chunk, extract the sequence number and the data
647634 */
648- residx = DatumGetInt32 (fastgetattr (ttup , 2 , toasttupDesc , & isnull ));
635+ curchunk = DatumGetInt32 (fastgetattr (ttup , 2 , toasttupDesc , & isnull ));
649636 Assert (!isnull );
650637 chunk = DatumGetPointer (fastgetattr (ttup , 3 , toasttupDesc , & isnull ));
651638 Assert (!isnull );
@@ -673,63 +660,60 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
673660 /*
674661 * Some checks on the data we've found
675662 */
676- if ((residx != nextidx ) || (residx > endchunk ) || (residx < startchunk ))
677- elog (ERROR , "unexpected chunk number %d (expected %d) for toast value %u in %s" ,
678- residx , nextidx ,
679- toast_pointer .va_valueid ,
680- RelationGetRelationName (toastrel ));
681- if (residx < totalchunks - 1 )
682- {
683- if (chunksize != TOAST_MAX_CHUNK_SIZE )
684- elog (ERROR , "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s when fetching slice" ,
685- chunksize , (int ) TOAST_MAX_CHUNK_SIZE ,
686- residx , totalchunks ,
687- toast_pointer .va_valueid ,
688- RelationGetRelationName (toastrel ));
689- }
690- else if (residx == totalchunks - 1 )
691- {
692- if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize ) != attrsize )
693- elog (ERROR , "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u in %s when fetching slice" ,
694- chunksize ,
695- (int ) (attrsize - residx * TOAST_MAX_CHUNK_SIZE ),
696- residx ,
697- toast_pointer .va_valueid ,
698- RelationGetRelationName (toastrel ));
699- }
700- else
701- elog (ERROR , "unexpected chunk number %d (out of range %d..%d) for toast value %u in %s" ,
702- residx ,
703- 0 , totalchunks - 1 ,
704- toast_pointer .va_valueid ,
705- RelationGetRelationName (toastrel ));
663+ if (curchunk != expectedchunk )
664+ ereport (ERROR ,
665+ (errcode (ERRCODE_DATA_CORRUPTED ),
666+ errmsg_internal ("unexpected chunk number %d (expected %d) for toast value %u in %s" ,
667+ curchunk , expectedchunk ,
668+ toast_pointer .va_valueid ,
669+ RelationGetRelationName (toastrel ))));
670+ if (curchunk > endchunk )
671+ ereport (ERROR ,
672+ (errcode (ERRCODE_DATA_CORRUPTED ),
673+ errmsg_internal ("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s" ,
674+ curchunk ,
675+ startchunk , endchunk ,
676+ toast_pointer .va_valueid ,
677+ RelationGetRelationName (toastrel ))));
678+ expected_size = curchunk < totalchunks - 1 ? TOAST_MAX_CHUNK_SIZE
679+ : attrsize % TOAST_MAX_CHUNK_SIZE ;
680+ if (chunksize != expected_size )
681+ ereport (ERROR ,
682+ (errcode (ERRCODE_DATA_CORRUPTED ),
683+ errmsg_internal ("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s" ,
684+ chunksize , expected_size ,
685+ curchunk , totalchunks ,
686+ toast_pointer .va_valueid ,
687+ RelationGetRelationName (toastrel ))));
706688
707689 /*
708690 * Copy the data into proper place in our result
709691 */
710692 chcpystrt = 0 ;
711693 chcpyend = chunksize - 1 ;
712- if (residx == startchunk )
713- chcpystrt = startoffset ;
714- if (residx == endchunk )
715- chcpyend = endoffset ;
694+ if (curchunk == startchunk )
695+ chcpystrt = sliceoffset % TOAST_MAX_CHUNK_SIZE ;
696+ if (curchunk == endchunk )
697+ chcpyend = ( sliceoffset + slicelength - 1 ) % TOAST_MAX_CHUNK_SIZE ;
716698
717699 memcpy (VARDATA (result ) +
718- (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset ) + chcpystrt ,
700+ (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset ) + chcpystrt ,
719701 chunkdata + chcpystrt ,
720702 (chcpyend - chcpystrt ) + 1 );
721703
722- nextidx ++ ;
704+ expectedchunk ++ ;
723705 }
724706
725707 /*
726708 * Final checks that we successfully fetched the datum
727709 */
728- if (nextidx != (endchunk + 1 ))
729- elog (ERROR , "missing chunk number %d for toast value %u in %s" ,
730- nextidx ,
731- toast_pointer .va_valueid ,
732- RelationGetRelationName (toastrel ));
710+ if (expectedchunk != (endchunk + 1 ))
711+ ereport (ERROR ,
712+ (errcode (ERRCODE_DATA_CORRUPTED ),
713+ errmsg_internal ("missing chunk number %d for toast value %u in %s" ,
714+ expectedchunk ,
715+ toast_pointer .va_valueid ,
716+ RelationGetRelationName (toastrel ))));
733717
734718 /*
735719 * End scan and close relations
0 commit comments