22
22
23
23
#include "access/xact.h"
24
24
#include "catalog/pg_type.h"
25
+ #include "common/int.h"
25
26
#include "common/int128.h"
26
27
#include "funcapi.h"
27
28
#include "libpq/pqformat.h"
@@ -3189,19 +3190,13 @@ interval_mul(PG_FUNCTION_ARGS)
3189
3190
result = (Interval * ) palloc (sizeof (Interval ));
3190
3191
3191
3192
result_double = span -> month * factor ;
3192
- if (isnan (result_double ) ||
3193
- result_double > INT_MAX || result_double < INT_MIN )
3194
- ereport (ERROR ,
3195
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3196
- errmsg ("interval out of range" )));
3193
+ if (isnan (result_double ) || !FLOAT8_FITS_IN_INT32 (result_double ))
3194
+ goto out_of_range ;
3197
3195
result -> month = (int32 ) result_double ;
3198
3196
3199
3197
result_double = span -> day * factor ;
3200
- if (isnan (result_double ) ||
3201
- result_double > INT_MAX || result_double < INT_MIN )
3202
- ereport (ERROR ,
3203
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3204
- errmsg ("interval out of range" )));
3198
+ if (isnan (result_double ) || !FLOAT8_FITS_IN_INT32 (result_double ))
3199
+ goto out_of_range ;
3205
3200
result -> day = (int32 ) result_double ;
3206
3201
3207
3202
/*
@@ -3235,20 +3230,30 @@ interval_mul(PG_FUNCTION_ARGS)
3235
3230
*/
3236
3231
if (Abs (sec_remainder ) >= SECS_PER_DAY )
3237
3232
{
3238
- result -> day += (int ) (sec_remainder / SECS_PER_DAY );
3233
+ if (pg_add_s32_overflow (result -> day ,
3234
+ (int ) (sec_remainder / SECS_PER_DAY ),
3235
+ & result -> day ))
3236
+ goto out_of_range ;
3239
3237
sec_remainder -= (int ) (sec_remainder / SECS_PER_DAY ) * SECS_PER_DAY ;
3240
3238
}
3241
3239
3242
3240
/* cascade units down */
3243
- result -> day += (int32 ) month_remainder_days ;
3241
+ if (pg_add_s32_overflow (result -> day , (int32 ) month_remainder_days ,
3242
+ & result -> day ))
3243
+ goto out_of_range ;
3244
3244
result_double = rint (span -> time * factor + sec_remainder * USECS_PER_SEC );
3245
3245
if (isnan (result_double ) || !FLOAT8_FITS_IN_INT64 (result_double ))
3246
- ereport (ERROR ,
3247
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3248
- errmsg ("interval out of range" )));
3246
+ goto out_of_range ;
3249
3247
result -> time = (int64 ) result_double ;
3250
3248
3251
3249
PG_RETURN_INTERVAL_P (result );
3250
+
3251
+ out_of_range :
3252
+ ereport (ERROR ,
3253
+ errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3254
+ errmsg ("interval out of range" ));
3255
+
3256
+ PG_RETURN_NULL (); /* keep compiler quiet */
3252
3257
}
3253
3258
3254
3259
Datum
@@ -3267,7 +3272,8 @@ interval_div(PG_FUNCTION_ARGS)
3267
3272
Interval * span = PG_GETARG_INTERVAL_P (0 );
3268
3273
float8 factor = PG_GETARG_FLOAT8 (1 );
3269
3274
double month_remainder_days ,
3270
- sec_remainder ;
3275
+ sec_remainder ,
3276
+ result_double ;
3271
3277
int32 orig_month = span -> month ,
3272
3278
orig_day = span -> day ;
3273
3279
Interval * result ;
@@ -3279,8 +3285,15 @@ interval_div(PG_FUNCTION_ARGS)
3279
3285
(errcode (ERRCODE_DIVISION_BY_ZERO ),
3280
3286
errmsg ("division by zero" )));
3281
3287
3282
- result -> month = (int32 ) (span -> month / factor );
3283
- result -> day = (int32 ) (span -> day / factor );
3288
+ result_double = span -> month / factor ;
3289
+ if (isnan (result_double ) || !FLOAT8_FITS_IN_INT32 (result_double ))
3290
+ goto out_of_range ;
3291
+ result -> month = (int32 ) result_double ;
3292
+
3293
+ result_double = span -> day / factor ;
3294
+ if (isnan (result_double ) || !FLOAT8_FITS_IN_INT32 (result_double ))
3295
+ goto out_of_range ;
3296
+ result -> day = (int32 ) result_double ;
3284
3297
3285
3298
/*
3286
3299
* Fractional months full days into days. See comment in interval_mul().
@@ -3292,15 +3305,30 @@ interval_div(PG_FUNCTION_ARGS)
3292
3305
sec_remainder = TSROUND (sec_remainder );
3293
3306
if (Abs (sec_remainder ) >= SECS_PER_DAY )
3294
3307
{
3295
- result -> day += (int ) (sec_remainder / SECS_PER_DAY );
3308
+ if (pg_add_s32_overflow (result -> day ,
3309
+ (int ) (sec_remainder / SECS_PER_DAY ),
3310
+ & result -> day ))
3311
+ goto out_of_range ;
3296
3312
sec_remainder -= (int ) (sec_remainder / SECS_PER_DAY ) * SECS_PER_DAY ;
3297
3313
}
3298
3314
3299
3315
/* cascade units down */
3300
- result -> day += (int32 ) month_remainder_days ;
3301
- result -> time = rint (span -> time / factor + sec_remainder * USECS_PER_SEC );
3316
+ if (pg_add_s32_overflow (result -> day , (int32 ) month_remainder_days ,
3317
+ & result -> day ))
3318
+ goto out_of_range ;
3319
+ result_double = rint (span -> time / factor + sec_remainder * USECS_PER_SEC );
3320
+ if (isnan (result_double ) || !FLOAT8_FITS_IN_INT64 (result_double ))
3321
+ goto out_of_range ;
3322
+ result -> time = (int64 ) result_double ;
3302
3323
3303
3324
PG_RETURN_INTERVAL_P (result );
3325
+
3326
+ out_of_range :
3327
+ ereport (ERROR ,
3328
+ errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
3329
+ errmsg ("interval out of range" ));
3330
+
3331
+ PG_RETURN_NULL (); /* keep compiler quiet */
3304
3332
}
3305
3333
3306
3334
0 commit comments