Index: src/backend/utils/adt/timestamp.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v
retrieving revision 1.166
diff -c -c -r1.166 timestamp.c
*** src/backend/utils/adt/timestamp.c	3 Sep 2006 03:34:04 -0000	1.166
--- src/backend/utils/adt/timestamp.c	4 Sep 2006 03:49:21 -0000
***************
*** 2525,2541 ****
  	sec_remainder = (orig_day * (double)SECS_PER_DAY) * factor -
  			result->day * (double)SECS_PER_DAY +
  			(month_remainder_days - (int32) month_remainder_days) * SECS_PER_DAY;
  
  	/* cascade units down */
  	result->day += (int32) month_remainder_days;
  #ifdef HAVE_INT64_TIMESTAMP
  	result->time = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
  #else
! 	/*
! 	 *	TSROUND() needed to prevent -146:23:60.00 output on PowerPC for
! 	 *	SELECT interval '-41 mon -12 days -360:00' * 0.3;
! 	 */
! 	result->time = span->time * factor + TSROUND(sec_remainder);
  #endif
  
  	PG_RETURN_INTERVAL_P(result);
--- 2524,2547 ----
  	sec_remainder = (orig_day * (double)SECS_PER_DAY) * factor -
  			result->day * (double)SECS_PER_DAY +
  			(month_remainder_days - (int32) month_remainder_days) * SECS_PER_DAY;
+ 	/*
+ 	 *	Might have 24:00:00 hours due to rounding, or >24 hours because of
+ 	 *	time cascade from months and days.  It might still be >24 if the
+ 	 *	combination of cascade and the seconds factor operation itself.
+ 	 */
+ 	sec_remainder = TSROUND(sec_remainder);
+ 	if (Abs(sec_remainder) >= SECS_PER_DAY)
+ 	{
+ 		sec_remainder -= (int)(sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
+ 		result->day += (int)(sec_remainder / SECS_PER_DAY);
+ 	}
  
  	/* cascade units down */
  	result->day += (int32) month_remainder_days;
  #ifdef HAVE_INT64_TIMESTAMP
  	result->time = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
  #else
! 	result->time = span->time * factor + sec_remainder;
  #endif
  
  	PG_RETURN_INTERVAL_P(result);
***************
*** 2579,2584 ****
--- 2585,2596 ----
  	sec_remainder = (orig_day * (double)SECS_PER_DAY) / factor -
  			result->day * (double)SECS_PER_DAY +
  			(month_remainder_days - (int32) month_remainder_days) * SECS_PER_DAY;
+ 	sec_remainder = TSROUND(sec_remainder);
+ 	if (Abs(sec_remainder) >= SECS_PER_DAY)
+ 	{
+ 		sec_remainder -= (int)(sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
+ 		result->day += (int)(sec_remainder / SECS_PER_DAY);
+ 	}
  
  	/* cascade units down */
  	result->day += (int32) month_remainder_days;
***************
*** 2586,2592 ****
  	result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
  #else
  	/* See TSROUND comment in interval_mul(). */
! 	result->time = span->time / factor + TSROUND(sec_remainder);
  #endif
  
  	PG_RETURN_INTERVAL_P(result);
--- 2598,2604 ----
  	result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
  #else
  	/* See TSROUND comment in interval_mul(). */
! 	result->time = span->time / factor + sec_remainder;
  #endif
  
  	PG_RETURN_INTERVAL_P(result);
Index: src/include/utils/timestamp.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/timestamp.h,v
retrieving revision 1.62
diff -c -c -r1.62 timestamp.h
*** src/include/utils/timestamp.h	13 Jul 2006 16:49:20 -0000	1.62
--- src/include/utils/timestamp.h	4 Sep 2006 03:49:22 -0000
***************
*** 161,171 ****
  
  typedef double fsec_t;
  
! /* round off to MAX_TIMESTAMP_PRECISION decimal places */
! /* note: this is also used for rounding off intervals */
  #define TS_PREC_INV 1000000.0
  #define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
- #endif
  
  #define TIMESTAMP_MASK(b) (1 << (b))
  #define INTERVAL_MASK(b) (1 << (b))
--- 161,174 ----
  
  typedef double fsec_t;
  
! #endif
! 
! /*
!  *	Round off to MAX_TIMESTAMP_PRECISION decimal places.
!  *	Note: this is also used for rounding off intervals.
!  */
  #define TS_PREC_INV 1000000.0
  #define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
  
  #define TIMESTAMP_MASK(b) (1 << (b))
  #define INTERVAL_MASK(b) (1 << (b))
