@@ -60,6 +60,11 @@ typedef struct DeltaDeltaDecompressionIterator
6060 Simple8bRleDecompressionIterator delta_deltas ;
6161 Simple8bRleDecompressionIterator nulls ;
6262 bool has_nulls ;
63+
64+ /* for validating the last_value set in the header
65+ * and cross check with the iterator */
66+ uint64 last_value_to_return ;
67+ uint64 last_returned_value ;
6368} DeltaDeltaDecompressionIterator ;
6469
6570typedef struct DeltaDeltaCompressor
@@ -481,6 +486,44 @@ delta_delta_compressor_append_value(DeltaDeltaCompressor *compressor, int64 next
481486/**********************************************************************************/
482487/**********************************************************************************/
483488
489+ static inline uint32
490+ decompression_iterator_items_seen (const DeltaDeltaDecompressionIterator * iter )
491+ {
492+ if (iter -> has_nulls )
493+ {
494+ return iter -> nulls .num_elements_returned ;
495+ }
496+ else
497+ {
498+ return iter -> delta_deltas .num_elements_returned ;
499+ }
500+ }
501+
502+ static inline uint32
503+ decompression_iterator_item_count (const DeltaDeltaDecompressionIterator * iter )
504+ {
505+ if (iter -> has_nulls )
506+ {
507+ return iter -> nulls .num_elements ;
508+ }
509+ else
510+ {
511+ return iter -> delta_deltas .num_elements ;
512+ }
513+ }
514+
515+ static inline uint32
516+ decompression_iterator_values_seen (const DeltaDeltaDecompressionIterator * iter )
517+ {
518+ return iter -> delta_deltas .num_elements_returned ;
519+ }
520+
521+ static inline uint32
522+ decompression_iterator_value_count (const DeltaDeltaDecompressionIterator * iter )
523+ {
524+ return iter -> delta_deltas .num_elements ;
525+ }
526+
484527static void
485528int64_decompression_iterator_init_forward (DeltaDeltaDecompressionIterator * iter , void * compressed ,
486529 Oid element_type )
@@ -507,6 +550,8 @@ int64_decompression_iterator_init_forward(DeltaDeltaDecompressionIterator *iter,
507550 .prev_val = 0 ,
508551 .prev_delta = 0 ,
509552 .has_nulls = has_nulls ,
553+ .last_returned_value = 0 ,
554+ .last_value_to_return = header -> last_value ,
510555 };
511556
512557 simple8brle_decompression_iterator_init_forward (& iter -> delta_deltas , deltas );
@@ -515,9 +560,13 @@ int64_decompression_iterator_init_forward(DeltaDeltaDecompressionIterator *iter,
515560 {
516561 Simple8bRleSerialized * nulls = bytes_deserialize_simple8b_and_advance (& si );
517562 simple8brle_decompression_iterator_init_forward (& iter -> nulls , nulls );
563+ CheckCompressedData (deltas -> num_elements <= nulls -> num_elements );
518564 }
519565}
520566
567+ static DecompressResultInternal
568+ delta_delta_decompression_iterator_try_next_forward_internal (DeltaDeltaDecompressionIterator * iter );
569+
521570static void
522571int64_decompression_iterator_init_reverse (DeltaDeltaDecompressionIterator * iter , void * compressed ,
523572 Oid element_type )
@@ -529,7 +578,7 @@ int64_decompression_iterator_init_reverse(DeltaDeltaDecompressionIterator *iter,
529578 DeltaDeltaCompressed * header = consumeCompressedData (& si , sizeof (DeltaDeltaCompressed ));
530579 Simple8bRleSerialized * deltas = bytes_deserialize_simple8b_and_advance (& si );
531580
532- Assert (header -> has_nulls == 0 || header -> has_nulls == 1 );
581+ CheckCompressedData (header -> has_nulls == 0 || header -> has_nulls == 1 );
533582
534583 * iter = (DeltaDeltaDecompressionIterator ){
535584 .base = {
@@ -541,6 +590,8 @@ int64_decompression_iterator_init_reverse(DeltaDeltaDecompressionIterator *iter,
541590 .prev_val = header -> last_value ,
542591 .prev_delta = header -> last_delta ,
543592 .has_nulls = header -> has_nulls ,
593+ .last_returned_value = 0 ,
594+ .last_value_to_return = 0 ,
544595 };
545596
546597 simple8brle_decompression_iterator_init_reverse (& iter -> delta_deltas , deltas );
@@ -549,6 +600,31 @@ int64_decompression_iterator_init_reverse(DeltaDeltaDecompressionIterator *iter,
549600 {
550601 Simple8bRleSerialized * nulls = bytes_deserialize_simple8b_and_advance (& si );
551602 simple8brle_decompression_iterator_init_reverse (& iter -> nulls , nulls );
603+ CheckCompressedData (deltas -> num_elements <= nulls -> num_elements );
604+ }
605+
606+ /* on reverse iteration the `last_value` in the header is critical for
607+ * the rest of the decoding. when we receive malformed data we can only
608+ * cross reference the result with the first value
609+ */
610+ {
611+ DeltaDeltaDecompressionIterator forward_iter ;
612+ forward_iter .base .compression_algorithm = COMPRESSION_ALGORITHM_DELTADELTA ;
613+ forward_iter .base .forward = true;
614+ forward_iter .base .element_type = element_type ;
615+ forward_iter .base .try_next = delta_delta_decompression_iterator_try_next_forward ;
616+ int64_decompression_iterator_init_forward (& forward_iter , compressed , element_type );
617+ /* find the first non-null value */
618+ DecompressResultInternal first_val =
619+ delta_delta_decompression_iterator_try_next_forward_internal (& forward_iter );
620+ int32 n = 0 ;
621+ while (first_val .is_done == false && first_val .is_null )
622+ {
623+ CheckCompressedData (n ++ < GLOBAL_MAX_ROWS_PER_COMPRESSION );
624+ first_val = delta_delta_decompression_iterator_try_next_forward_internal (& forward_iter );
625+ }
626+ CheckCompressedData (!first_val .is_done );
627+ iter -> last_value_to_return = first_val .val ;
552628 }
553629}
554630
@@ -615,6 +691,14 @@ delta_delta_decompression_iterator_try_next_forward_internal(DeltaDeltaDecompres
615691 simple8brle_decompression_iterator_try_next_forward (& iter -> nulls );
616692 if (result .is_done )
617693 {
694+ /* make sure we exhausted all items before */
695+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
696+ decompression_iterator_item_count (iter ));
697+ /* and also that we returned all values */
698+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
699+ decompression_iterator_value_count (iter ));
700+ /* the last element must match the expected value */
701+ CheckCompressedData (iter -> last_returned_value == iter -> last_value_to_return );
618702 return (DecompressResultInternal ){
619703 .is_done = true,
620704 };
@@ -633,6 +717,14 @@ delta_delta_decompression_iterator_try_next_forward_internal(DeltaDeltaDecompres
633717
634718 if (result .is_done )
635719 {
720+ /* make sure we exhausted all items before */
721+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
722+ decompression_iterator_item_count (iter ));
723+ /* and also that we returned all values */
724+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
725+ decompression_iterator_value_count (iter ));
726+ /* the last element must match the expected value */
727+ CheckCompressedData (iter -> last_returned_value == iter -> last_value_to_return );
636728 return (DecompressResultInternal ){
637729 .is_done = true,
638730 };
@@ -642,6 +734,7 @@ delta_delta_decompression_iterator_try_next_forward_internal(DeltaDeltaDecompres
642734
643735 iter -> prev_delta += delta_delta ;
644736 iter -> prev_val += iter -> prev_delta ;
737+ iter -> last_returned_value = iter -> prev_val ;
645738
646739 return (DecompressResultInternal ){
647740 .val = iter -> prev_val ,
@@ -712,14 +805,22 @@ delta_delta_decompression_iterator_try_next_reverse_internal(DeltaDeltaDecompres
712805 simple8brle_decompression_iterator_try_next_reverse (& iter -> nulls );
713806 if (result .is_done )
714807 {
808+ /* make sure we exhausted all items before */
809+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
810+ decompression_iterator_item_count (iter ));
811+ /* and also that we returned all values */
812+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
813+ decompression_iterator_value_count (iter ));
814+ /* the last element must match the expected value */
815+ CheckCompressedData (iter -> last_returned_value == iter -> last_value_to_return );
715816 return (DecompressResultInternal ){
716817 .is_done = true,
717818 };
718819 }
719820
720821 if (result .val != 0 )
721822 {
722- Assert (result .val == 1 );
823+ CheckCompressedData (result .val == 1 );
723824 return (DecompressResultInternal ){
724825 .is_null = true,
725826 };
@@ -730,6 +831,14 @@ delta_delta_decompression_iterator_try_next_reverse_internal(DeltaDeltaDecompres
730831
731832 if (result .is_done )
732833 {
834+ /* make sure we exhausted all items before */
835+ CheckCompressedData (decompression_iterator_items_seen (iter ) ==
836+ decompression_iterator_item_count (iter ));
837+ /* and also that we returned all values */
838+ CheckCompressedData (decompression_iterator_values_seen (iter ) ==
839+ decompression_iterator_value_count (iter ));
840+ /* the last element must match the expected value */
841+ CheckCompressedData (iter -> last_returned_value == iter -> last_value_to_return );
733842 return (DecompressResultInternal ){
734843 .is_done = true,
735844 };
@@ -740,6 +849,7 @@ delta_delta_decompression_iterator_try_next_reverse_internal(DeltaDeltaDecompres
740849 delta_delta = zig_zag_decode (result .val );
741850 iter -> prev_val -= iter -> prev_delta ;
742851 iter -> prev_delta -= delta_delta ;
852+ iter -> last_returned_value = val ;
743853
744854 return (DecompressResultInternal ){
745855 .val = val ,
0 commit comments