@@ -3315,19 +3315,13 @@ interval_mul(PG_FUNCTION_ARGS)
33153315	result  =  (Interval  * ) palloc (sizeof (Interval ));
33163316
33173317	result_double  =  span -> month  *  factor ;
3318- 	if  (isnan (result_double ) || 
3319- 		result_double  >  INT_MAX  ||  result_double  <  INT_MIN )
3320- 		ereport (ERROR ,
3321- 				(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3322- 				 errmsg ("interval out of range" )));
3318+ 	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT32 (result_double ))
3319+ 		goto out_of_range ;
33233320	result -> month  =  (int32 ) result_double ;
33243321
33253322	result_double  =  span -> day  *  factor ;
3326- 	if  (isnan (result_double ) || 
3327- 		result_double  >  INT_MAX  ||  result_double  <  INT_MIN )
3328- 		ereport (ERROR ,
3329- 				(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3330- 				 errmsg ("interval out of range" )));
3323+ 	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT32 (result_double ))
3324+ 		goto out_of_range ;
33313325	result -> day  =  (int32 ) result_double ;
33323326
33333327	/* 
@@ -3361,20 +3355,30 @@ interval_mul(PG_FUNCTION_ARGS)
33613355	 */ 
33623356	if  (fabs (sec_remainder ) >= SECS_PER_DAY )
33633357	{
3364- 		result -> day  +=  (int ) (sec_remainder  / SECS_PER_DAY );
3358+ 		if  (pg_add_s32_overflow (result -> day ,
3359+ 								(int ) (sec_remainder  / SECS_PER_DAY ),
3360+ 								& result -> day ))
3361+ 			goto out_of_range ;
33653362		sec_remainder  -=  (int ) (sec_remainder  / SECS_PER_DAY ) *  SECS_PER_DAY ;
33663363	}
33673364
33683365	/* cascade units down */ 
3369- 	result -> day  +=  (int32 ) month_remainder_days ;
3366+ 	if  (pg_add_s32_overflow (result -> day , (int32 ) month_remainder_days ,
3367+ 							& result -> day ))
3368+ 		goto out_of_range ;
33703369	result_double  =  rint (span -> time  *  factor  +  sec_remainder  *  USECS_PER_SEC );
33713370	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT64 (result_double ))
3372- 		ereport (ERROR ,
3373- 				(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3374- 				 errmsg ("interval out of range" )));
3371+ 		goto out_of_range ;
33753372	result -> time  =  (int64 ) result_double ;
33763373
33773374	PG_RETURN_INTERVAL_P (result );
3375+ 
3376+ out_of_range :
3377+ 	ereport (ERROR ,
3378+ 			errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3379+ 			errmsg ("interval out of range" ));
3380+ 
3381+ 	PG_RETURN_NULL ();			/* keep compiler quiet */ 
33783382}
33793383
33803384Datum 
@@ -3393,7 +3397,8 @@ interval_div(PG_FUNCTION_ARGS)
33933397	Interval    * span  =  PG_GETARG_INTERVAL_P (0 );
33943398	float8 		factor  =  PG_GETARG_FLOAT8 (1 );
33953399	double 		month_remainder_days ,
3396- 				sec_remainder ;
3400+ 				sec_remainder ,
3401+ 				result_double ;
33973402	int32 		orig_month  =  span -> month ,
33983403				orig_day  =  span -> day ;
33993404	Interval    * result ;
@@ -3405,8 +3410,15 @@ interval_div(PG_FUNCTION_ARGS)
34053410				(errcode (ERRCODE_DIVISION_BY_ZERO ),
34063411				 errmsg ("division by zero" )));
34073412
3408- 	result -> month  =  (int32 ) (span -> month  / factor );
3409- 	result -> day  =  (int32 ) (span -> day  / factor );
3413+ 	result_double  =  span -> month  / factor ;
3414+ 	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT32 (result_double ))
3415+ 		goto out_of_range ;
3416+ 	result -> month  =  (int32 ) result_double ;
3417+ 
3418+ 	result_double  =  span -> day  / factor ;
3419+ 	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT32 (result_double ))
3420+ 		goto out_of_range ;
3421+ 	result -> day  =  (int32 ) result_double ;
34103422
34113423	/* 
34123424	 * Fractional months full days into days.  See comment in interval_mul(). 
@@ -3418,15 +3430,30 @@ interval_div(PG_FUNCTION_ARGS)
34183430	sec_remainder  =  TSROUND (sec_remainder );
34193431	if  (fabs (sec_remainder ) >= SECS_PER_DAY )
34203432	{
3421- 		result -> day  +=  (int ) (sec_remainder  / SECS_PER_DAY );
3433+ 		if  (pg_add_s32_overflow (result -> day ,
3434+ 								(int ) (sec_remainder  / SECS_PER_DAY ),
3435+ 								& result -> day ))
3436+ 			goto out_of_range ;
34223437		sec_remainder  -=  (int ) (sec_remainder  / SECS_PER_DAY ) *  SECS_PER_DAY ;
34233438	}
34243439
34253440	/* cascade units down */ 
3426- 	result -> day  +=  (int32 ) month_remainder_days ;
3427- 	result -> time  =  rint (span -> time  / factor  +  sec_remainder  *  USECS_PER_SEC );
3441+ 	if  (pg_add_s32_overflow (result -> day , (int32 ) month_remainder_days ,
3442+ 							& result -> day ))
3443+ 		goto out_of_range ;
3444+ 	result_double  =  rint (span -> time  / factor  +  sec_remainder  *  USECS_PER_SEC );
3445+ 	if  (isnan (result_double ) ||  !FLOAT8_FITS_IN_INT64 (result_double ))
3446+ 		goto out_of_range ;
3447+ 	result -> time  =  (int64 ) result_double ;
34283448
34293449	PG_RETURN_INTERVAL_P (result );
3450+ 
3451+ out_of_range :
3452+ 	ereport (ERROR ,
3453+ 			errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3454+ 			errmsg ("interval out of range" ));
3455+ 
3456+ 	PG_RETURN_NULL ();			/* keep compiler quiet */ 
34303457}
34313458
34323459
0 commit comments