Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6a9b93a

Browse files
committed
Remove justify_hours call from interval_mul and interval_div, and make
some small stylistic improvements in these functions. Also fix severalplaces where TMODULO() was being used with wrong-sized quotient argument,creating a risk of overflow --- interval2tm was actually capable of goinginto an infinite loop because of this.
1 parentc78f303 commit6a9b93a

File tree

2 files changed

+76
-48
lines changed

2 files changed

+76
-48
lines changed

‎src/backend/utils/adt/timestamp.c

Lines changed: 75 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.155 2005/10/15 02:49:30 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.156 2005/10/25 17:13:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1224,8 +1224,10 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
12241224
{
12251225
#ifdefHAVE_INT64_TIMESTAMP
12261226
int64time;
1227+
int64tfrac;
12271228
#else
12281229
doubletime;
1230+
doubletfrac;
12291231
#endif
12301232

12311233
tm->tm_year=span.month /MONTHS_PER_YEAR;
@@ -1234,17 +1236,23 @@ interval2tm(Interval span, struct pg_tm * tm, fsec_t *fsec)
12341236
time=span.time;
12351237

12361238
#ifdefHAVE_INT64_TIMESTAMP
1237-
tm->tm_hour=time /USECS_PER_HOUR;
1238-
time-=tm->tm_hour*USECS_PER_HOUR;
1239-
tm->tm_min=time /USECS_PER_MINUTE;
1240-
time-=tm->tm_min*USECS_PER_MINUTE;
1241-
tm->tm_sec=time /USECS_PER_SEC;
1242-
*fsec=time- (tm->tm_sec*USECS_PER_SEC);
1239+
tfrac=time /USECS_PER_HOUR;
1240+
time-=tfrac*USECS_PER_HOUR;
1241+
tm->tm_hour=tfrac;/* could overflow ... */
1242+
tfrac=time /USECS_PER_MINUTE;
1243+
time-=tfrac*USECS_PER_MINUTE;
1244+
tm->tm_min=tfrac;
1245+
tfrac=time /USECS_PER_SEC;
1246+
*fsec=time- (tfrac*USECS_PER_SEC);
1247+
tm->tm_sec=tfrac;
12431248
#else
12441249
recalc:
1245-
TMODULO(time,tm->tm_hour, (double)SECS_PER_HOUR);
1246-
TMODULO(time,tm->tm_min, (double)SECS_PER_MINUTE);
1247-
TMODULO(time,tm->tm_sec,1.0);
1250+
TMODULO(time,tfrac, (double)SECS_PER_HOUR);
1251+
tm->tm_hour=tfrac;/* could overflow ... */
1252+
TMODULO(time,tfrac, (double)SECS_PER_MINUTE);
1253+
tm->tm_min=tfrac;
1254+
TMODULO(time,tfrac,1.0);
1255+
tm->tm_sec=tfrac;
12481256
time=TSROUND(time);
12491257
/* roundoff may need to propagate to higher-order fields */
12501258
if (time >=1.0)
@@ -1935,55 +1943,68 @@ timestamp_mi(PG_FUNCTION_ARGS)
19351943
result->month=0;
19361944
result->day=0;
19371945

1946+
/* this is wrong, but removing it breaks a lot of regression tests */
19381947
result=DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
19391948
IntervalPGetDatum(result)));
1949+
19401950
PG_RETURN_INTERVAL_P(result);
19411951
}
19421952

1943-
/*interval_justify_hours()
1944-
*Adjust interval so 'time' contains less than a whole day, and
1945-
*'day' contains an integral number of days.This is useful for
1953+
/*
1954+
*interval_justify_hours()
1955+
*
1956+
*Adjust interval so 'time' contains less than a whole day, adding
1957+
*the excess to 'day'. This is useful for
19461958
*situations (such as non-TZ) where '1 day' = '24 hours' is valid,
1947-
*e.g. interval subtraction and division. The SQL standard requires
1948-
*such conversion in these cases, but not the conversion of days to months.
1959+
*e.g. interval subtraction and division.
19491960
*/
19501961
Datum
19511962
interval_justify_hours(PG_FUNCTION_ARGS)
19521963
{
19531964
Interval*span=PG_GETARG_INTERVAL_P(0);
19541965
Interval*result;
1966+
#ifdefHAVE_INT64_TIMESTAMP
1967+
int64wholeday;
1968+
#else
1969+
doublewholeday;
1970+
#endif
19551971

19561972
result= (Interval*)palloc(sizeof(Interval));
19571973
result->month=span->month;
1974+
result->day=span->day;
19581975
result->time=span->time;
19591976

19601977
#ifdefHAVE_INT64_TIMESTAMP
1961-
result->time+=span->day*USECS_PER_DAY;
1962-
TMODULO(result->time,result->day,USECS_PER_DAY);
1978+
TMODULO(result->time,wholeday,USECS_PER_DAY);
19631979
#else
1964-
result->time+=span->day* (double)SECS_PER_DAY;
1965-
TMODULO(result->time,result->day, (double)SECS_PER_DAY);
1980+
TMODULO(result->time,wholeday, (double)SECS_PER_DAY);
19661981
#endif
1982+
result->day+=wholeday;/* could overflow... */
19671983

19681984
PG_RETURN_INTERVAL_P(result);
19691985
}
19701986

1971-
/*interval_justify_days()
1972-
*Adjust interval so 'time' contains less than 30 days, and
1973-
*adds as months.
1987+
/*
1988+
*interval_justify_days()
1989+
*
1990+
*Adjust interval so 'day' contains less than 30 days, adding
1991+
*the excess to 'month'.
19741992
*/
19751993
Datum
19761994
interval_justify_days(PG_FUNCTION_ARGS)
19771995
{
19781996
Interval*span=PG_GETARG_INTERVAL_P(0);
19791997
Interval*result;
1998+
int32wholemonth;
19801999

19812000
result= (Interval*)palloc(sizeof(Interval));
2001+
result->month=span->month;
19822002
result->day=span->day;
19832003
result->time=span->time;
19842004

1985-
result->day+=span->month*DAYS_PER_MONTH;
1986-
TMODULO(result->day,result->month,DAYS_PER_MONTH);
2005+
wholemonth=result->day /DAYS_PER_MONTH;
2006+
result->day-=wholemonth*DAYS_PER_MONTH;
2007+
result->month+=wholemonth;
19872008

19882009
PG_RETURN_INTERVAL_P(result);
19892010
}
@@ -2282,28 +2303,35 @@ interval_mul(PG_FUNCTION_ARGS)
22822303

22832304
result= (Interval*)palloc(sizeof(Interval));
22842305

2285-
result->month=span->month*factor;
2286-
result->day=span->day*factor;
2306+
month_remainder=span->month*factor;
2307+
day_remainder=span->day*factor;
2308+
result->month= (int32)month_remainder;
2309+
result->day= (int32)day_remainder;
2310+
month_remainder-=result->month;
2311+
day_remainder-=result->day;
22872312

2288-
/* Compute remainders */
2289-
month_remainder=span->month*factor-result->month;
2290-
day_remainder=span->day*factor-result->day;
2313+
/*
2314+
* The above correctly handles the whole-number part of the month and
2315+
* day products, but we have to do something with any fractional part
2316+
* resulting when the factor is nonintegral. We cascade the fractions
2317+
* down to lower units using the conversion factors DAYS_PER_MONTH and
2318+
* SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to
2319+
* do so by the representation. The user can choose to cascade up later,
2320+
* using justify_hours and/or justify_days.
2321+
*/
22912322

2292-
/* Cascade fractions to lower units */
22932323
/* fractional months full days into days */
22942324
month_remainder_days=month_remainder*DAYS_PER_MONTH;
2295-
result->day+=month_remainder_days;
2325+
result->day+=(int32)month_remainder_days;
22962326
/* fractional months partial days into time */
2297-
day_remainder+=month_remainder_days- (int)month_remainder_days;
2327+
day_remainder+=month_remainder_days- (int32)month_remainder_days;
22982328

22992329
#ifdefHAVE_INT64_TIMESTAMP
23002330
result->time=rint(span->time*factor+day_remainder*USECS_PER_DAY);
23012331
#else
23022332
result->time=span->time*factor+day_remainder*SECS_PER_DAY;
23032333
#endif
23042334

2305-
result=DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2306-
IntervalPGetDatum(result)));
23072335
PG_RETURN_INTERVAL_P(result);
23082336
}
23092337

@@ -2334,29 +2362,29 @@ interval_div(PG_FUNCTION_ARGS)
23342362
(errcode(ERRCODE_DIVISION_BY_ZERO),
23352363
errmsg("division by zero")));
23362364

2337-
result->month=span->month /factor;
2338-
result->day=span->day /factor;
2339-
result->time=span->time /factor;
2365+
month_remainder=span->month /factor;
2366+
day_remainder=span->day /factor;
2367+
result->month= (int32)month_remainder;
2368+
result->day= (int32)day_remainder;
2369+
month_remainder-=result->month;
2370+
day_remainder-=result->day;
23402371

2341-
/* Compute remainders */
2342-
month_remainder=span->month /factor-result->month;
2343-
day_remainder=span->day /factor-result->day;
2372+
/*
2373+
* Handle any fractional parts the same way as in interval_mul.
2374+
*/
23442375

2345-
/* Cascade fractions to lower units */
23462376
/* fractional months full days into days */
23472377
month_remainder_days=month_remainder*DAYS_PER_MONTH;
2348-
result->day+=month_remainder_days;
2378+
result->day+=(int32)month_remainder_days;
23492379
/* fractional months partial days into time */
2350-
day_remainder+=month_remainder_days- (int)month_remainder_days;
2380+
day_remainder+=month_remainder_days- (int32)month_remainder_days;
23512381

23522382
#ifdefHAVE_INT64_TIMESTAMP
2353-
result->time+=rint(day_remainder*USECS_PER_DAY);
2383+
result->time=rint(span->time /factor+day_remainder*USECS_PER_DAY);
23542384
#else
2355-
result->time+=day_remainder*SECS_PER_DAY;
2385+
result->time=span->time /factor+day_remainder*SECS_PER_DAY;
23562386
#endif
23572387

2358-
result=DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2359-
IntervalPGetDatum(result)));
23602388
PG_RETURN_INTERVAL_P(result);
23612389
}
23622390

‎src/test/regress/expected/interval.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ SELECT '' AS ten, * FROM INTERVAL_TBL;
218218
select avg(f1) from interval_tbl;
219219
avg
220220
-------------------------------------------------
221-
@ 4 years 1 mon10 days4 hours 18 mins 23 secs
221+
@ 4 years 1 mon9 days28 hours 18 mins 23 secs
222222
(1 row)
223223

224224
-- test long interval input

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp