3131#include "utils/relmapper.h"
3232#include "utils/syscache.h"
3333
34+ /* Divide by two and round towards positive infinity. */
35+ #define half_rounded (x ) (((x) + ((x) < 0 ? 0 : 1)) / 2)
3436
3537/* Return physical size of directory contents, or 0 if dir doesn't exist */
3638static int64
@@ -534,31 +536,31 @@ pg_size_pretty(PG_FUNCTION_ARGS)
534536 int64 limit = 10 * 1024 ;
535537 int64 limit2 = limit * 2 - 1 ;
536538
537- if (size < limit )
539+ if (Abs ( size ) < limit )
538540 snprintf (buf , sizeof (buf ), INT64_FORMAT " bytes" , size );
539541 else
540542 {
541543 size >>= 9 ; /* keep one extra bit for rounding */
542- if (size < limit2 )
544+ if (Abs ( size ) < limit2 )
543545 snprintf (buf , sizeof (buf ), INT64_FORMAT " kB" ,
544- (size + 1 ) / 2 );
546+ half_rounded (size ) );
545547 else
546548 {
547549 size >>= 10 ;
548- if (size < limit2 )
550+ if (Abs ( size ) < limit2 )
549551 snprintf (buf , sizeof (buf ), INT64_FORMAT " MB" ,
550- (size + 1 ) / 2 );
552+ half_rounded (size ) );
551553 else
552554 {
553555 size >>= 10 ;
554- if (size < limit2 )
556+ if (Abs ( size ) < limit2 )
555557 snprintf (buf , sizeof (buf ), INT64_FORMAT " GB" ,
556- (size + 1 ) / 2 );
558+ half_rounded (size ) );
557559 else
558560 {
559561 size >>= 10 ;
560562 snprintf (buf , sizeof (buf ), INT64_FORMAT " TB" ,
561- (size + 1 ) / 2 );
563+ half_rounded (size ) );
562564 }
563565 }
564566 }
@@ -593,17 +595,34 @@ numeric_is_less(Numeric a, Numeric b)
593595}
594596
595597static Numeric
596- numeric_plus_one_over_two (Numeric n )
598+ numeric_absolute (Numeric n )
597599{
598600 Datum d = NumericGetDatum (n );
601+ Datum result ;
602+
603+ result = DirectFunctionCall1 (numeric_abs , d );
604+ return DatumGetNumeric (result );
605+ }
606+
607+ static Numeric
608+ numeric_half_rounded (Numeric n )
609+ {
610+ Datum d = NumericGetDatum (n );
611+ Datum zero ;
599612 Datum one ;
600613 Datum two ;
601614 Datum result ;
602615
616+ zero = DirectFunctionCall1 (int8_numeric , Int64GetDatum (0 ));
603617 one = DirectFunctionCall1 (int8_numeric , Int64GetDatum (1 ));
604618 two = DirectFunctionCall1 (int8_numeric , Int64GetDatum (2 ));
605- result = DirectFunctionCall2 (numeric_add , d , one );
606- result = DirectFunctionCall2 (numeric_div_trunc , result , two );
619+
620+ if (DatumGetBool (DirectFunctionCall2 (numeric_ge , d , zero )))
621+ d = DirectFunctionCall2 (numeric_add , d , one );
622+ else
623+ d = DirectFunctionCall2 (numeric_sub , d , one );
624+
625+ result = DirectFunctionCall2 (numeric_div_trunc , d , two );
607626 return DatumGetNumeric (result );
608627}
609628
@@ -632,7 +651,7 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
632651 limit = int64_to_numeric (10 * 1024 );
633652 limit2 = int64_to_numeric (10 * 1024 * 2 - 1 );
634653
635- if (numeric_is_less (size , limit ))
654+ if (numeric_is_less (numeric_absolute ( size ) , limit ))
636655 {
637656 result = psprintf ("%s bytes" , numeric_to_cstring (size ));
638657 }
@@ -642,39 +661,35 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
642661 /* size >>= 9 */
643662 size = numeric_shift_right (size , 9 );
644663
645- if (numeric_is_less (size , limit2 ))
664+ if (numeric_is_less (numeric_absolute ( size ) , limit2 ))
646665 {
647- /* size = (size + 1) / 2 */
648- size = numeric_plus_one_over_two (size );
666+ size = numeric_half_rounded (size );
649667 result = psprintf ("%s kB" , numeric_to_cstring (size ));
650668 }
651669 else
652670 {
653671 /* size >>= 10 */
654672 size = numeric_shift_right (size , 10 );
655- if (numeric_is_less (size , limit2 ))
673+ if (numeric_is_less (numeric_absolute ( size ) , limit2 ))
656674 {
657- /* size = (size + 1) / 2 */
658- size = numeric_plus_one_over_two (size );
675+ size = numeric_half_rounded (size );
659676 result = psprintf ("%s MB" , numeric_to_cstring (size ));
660677 }
661678 else
662679 {
663680 /* size >>= 10 */
664681 size = numeric_shift_right (size , 10 );
665682
666- if (numeric_is_less (size , limit2 ))
683+ if (numeric_is_less (numeric_absolute ( size ) , limit2 ))
667684 {
668- /* size = (size + 1) / 2 */
669- size = numeric_plus_one_over_two (size );
685+ size = numeric_half_rounded (size );
670686 result = psprintf ("%s GB" , numeric_to_cstring (size ));
671687 }
672688 else
673689 {
674690 /* size >>= 10 */
675691 size = numeric_shift_right (size , 10 );
676- /* size = (size + 1) / 2 */
677- size = numeric_plus_one_over_two (size );
692+ size = numeric_half_rounded (size );
678693 result = psprintf ("%s TB" , numeric_to_cstring (size ));
679694 }
680695 }
0 commit comments