Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 424d938

Browse files
author
Thomas G. Lockhart
committed
Fix transposed arguments for typmod for one INTERVAL production.
Mask both typmod subfields for INTERVAL to avoid setting the high bit, per dire warning from Tom Lane. Clear tmask for DTK_ISO_TIME case to avoid time zone troubles. Symptom reported by Tom Lane. Clean up checking for valid time zone info in output routine. This should now work for both SQL99 and Unix-style time zones. Put in explicit check for INTERVAL() typmod rounding to avoid accumulating cruft in the lower bits. Not sure that this helps, but we'll need to do something. The symptom is visible with a query like select interval(2) '10000 days 01:02:03.040506'; Regression tests are patched to repair the Tom Lane symptom, and all pass.
1 parent 3a484d9 commit 424d938

File tree

6 files changed

+114
-57
lines changed

6 files changed

+114
-57
lines changed

src/backend/parser/gram.y

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.264 2001/10/18 23:16:09 tgl Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.265 2001/10/20 01:02:14 thomas Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -887,13 +887,18 @@ zone_value: Sconst
887887
| ConstInterval Sconst opt_interval
888888
{
889889
A_Const *n = (A_Const *) makeStringConst($2, $1);
890-
n->typename->typmod = (($3 << 16) | 0xFFFF);
890+
if ($3 != -1)
891+
n->typename->typmod = (($3 << 16) | 0xFFFF);
891892
$$ = (Node *)n;
892893
}
893894
| ConstInterval '(' Iconst ')' Sconst opt_interval
894895
{
895896
A_Const *n = (A_Const *) makeStringConst($5, $1);
896-
n->typename->typmod = (($3 << 16) | $6);
897+
if ($6 != -1)
898+
n->typename->typmod = (($6 << 16) | $3);
899+
else
900+
n->typename->typmod = ((0x7FFF << 16) | $3);
901+
897902
$$ = (Node *)n;
898903
}
899904
| FCONST
@@ -4044,12 +4049,13 @@ SimpleTypename: ConstTypename
40444049
| ConstInterval opt_interval
40454050
{
40464051
$$ = $1;
4047-
$$->typmod = (($2 << 16) | 0xFFFF);
4052+
if ($2 != -1)
4053+
$$->typmod = ((($2 & 0x7FFF) << 16) | 0xFFFF);
40484054
}
40494055
| ConstInterval '(' Iconst ')' opt_interval
40504056
{
40514057
$$ = $1;
4052-
$$->typmod = (($5 << 16) | $3);
4058+
$$->typmod = ((($5 & 0x7FFF) << 16) | $3);
40534059
}
40544060
;
40554061

@@ -5625,7 +5631,9 @@ AexprConst: Iconst
56255631
n->typename = $1;
56265632
n->val.type = T_String;
56275633
n->val.val.str = $2;
5628-
n->typename->typmod = (($3 << 16) | 0xFFFF);
5634+
/* precision is not specified, but fields may be... */
5635+
if ($3 != -1)
5636+
n->typename->typmod = ((($3 & 0x7FFF) << 16) | 0xFFFF);
56295637
$$ = (Node *)n;
56305638
}
56315639
| ConstInterval '(' Iconst ')' Sconst opt_interval
@@ -5634,7 +5642,9 @@ AexprConst: Iconst
56345642
n->typename = $1;
56355643
n->val.type = T_String;
56365644
n->val.val.str = $5;
5637-
n->typename->typmod = (($6 << 16) | $3);
5645+
/* precision specified, and fields may be... */
5646+
n->typename->typmod = ((($6 & 0x7FFF) << 16) | $3);
5647+
56385648
$$ = (Node *)n;
56395649
}
56405650
| ParamNo

src/backend/utils/adt/datetime.c

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.73 2001/10/18 17:30:15 thomas Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.74 2001/10/20 01:02:18 thomas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -385,17 +385,22 @@ j2day(int date)
385385
} /* j2day() */
386386

387387

388+
/* TrimTrailingZeros()
389+
* ... resulting from printing numbers with full precision.
390+
*/
388391
void
389392
TrimTrailingZeros(char *str)
390393
{
391394
int len = strlen(str);
392395

396+
#if 0
393397
/* chop off trailing one to cope with interval rounding */
394398
if (strcmp((str + len - 4), "0001") == 0)
395399
{
396400
len -= 4;
397401
*(str + len) = '\0';
398402
}
403+
#endif
399404

400405
/* chop off trailing zeros... */
401406
while ((*(str + len - 1) == '0')
@@ -905,11 +910,12 @@ DecodeDateTime(char **field, int *ftype, int nf,
905910
break;
906911

907912
case UNITS:
908-
ptype = val;
909913
tmask = 0;
914+
ptype = val;
910915
break;
911916

912917
case DTK_ISO_TIME:
918+
tmask = 0;
913919
if ((i < 1) || (i >= (nf-1))
914920
|| (ftype[i-1] != DTK_DATE)
915921
|| (ftype[i+1] != DTK_TIME))
@@ -2267,10 +2273,10 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
22672273
}
22682274

22692275
/* tzp == NULL indicates that we don't want *any* time zone info in the output string.
2270-
* *tzn != NULL indicates that we *have* time zone info available.
2276+
* *tzn != NULL indicates that we have alpha time zone info available.
22712277
* tm_isdst != -1 indicates that we have a valid time zone translation.
22722278
*/
2273-
if ((tzp != NULL) && (*tzn != NULL) && (tm->tm_isdst >= 0))
2279+
if ((tzp != NULL) && (tm->tm_isdst >= 0))
22742280
{
22752281
hour = -(*tzp / 3600);
22762282
min = ((abs(*tzp) / 60) % 60);
@@ -2315,14 +2321,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
23152321
sprintf((str + strlen(str)), ":%02.0f", sec);
23162322
}
23172323

2318-
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
2319-
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2320-
2321-
else if (tzp != NULL)
2324+
if ((tzp != NULL) && (tm->tm_isdst >= 0))
23222325
{
2323-
hour = -(*tzp / 3600);
2324-
min = ((abs(*tzp) / 60) % 60);
2325-
sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
2326+
if (*tzn != NULL)
2327+
{
2328+
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2329+
}
2330+
else
2331+
{
2332+
hour = -(*tzp / 3600);
2333+
min = ((abs(*tzp) / 60) % 60);
2334+
sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
2335+
}
23262336
}
23272337
}
23282338
else
@@ -2353,14 +2363,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
23532363
sprintf((str + strlen(str)), ":%02.0f", sec);
23542364
}
23552365

2356-
if ((*tzn != NULL) && (tm->tm_isdst >= 0))
2357-
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2358-
2359-
else if (tzp != NULL)
2366+
if ((tzp != NULL) && (tm->tm_isdst >= 0))
23602367
{
2361-
hour = -(*tzp / 3600);
2362-
min = ((abs(*tzp) / 60) % 60);
2363-
sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
2368+
if (*tzn != NULL)
2369+
{
2370+
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2371+
}
2372+
else
2373+
{
2374+
hour = -(*tzp / 3600);
2375+
min = ((abs(*tzp) / 60) % 60);
2376+
sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
2377+
}
23642378
}
23652379
}
23662380
else
@@ -2403,14 +2417,23 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
24032417

24042418
sprintf((str + strlen(str)), " %04d", tm->tm_year);
24052419

2406-
if ((tzp != NULL) && (*tzn != NULL) && (tm->tm_isdst >= 0))
2407-
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2408-
2409-
else if (HasCTZSet && (tzp != NULL))
2420+
if ((tzp != NULL) && (tm->tm_isdst >= 0))
24102421
{
2411-
hour = -(*tzp / 3600);
2412-
min = ((abs(*tzp) / 60) % 60);
2413-
sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
2422+
if (*tzn != NULL)
2423+
{
2424+
sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
2425+
}
2426+
else
2427+
{
2428+
/* We have a time zone, but no string version.
2429+
* Use the numeric form, but be sure to include a leading space
2430+
* to avoid formatting something which would be rejected by the
2431+
* date/time parser later. - thomas 2001-10-19
2432+
*/
2433+
hour = -(*tzp / 3600);
2434+
min = ((abs(*tzp) / 60) % 60);
2435+
sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
2436+
}
24142437
}
24152438
}
24162439
else

src/backend/utils/adt/nabstime.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.89 2001/10/18 19:52:03 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.90 2001/10/20 01:02:18 thomas Exp $
1313
*
1414
* NOTES
1515
*
@@ -256,7 +256,7 @@ GetCurrentAbsoluteTimeUsec(int *usec)
256256
};
257257

258258
return (AbsoluteTime) now;
259-
} /* GetCurrentAbsoluteTime() */
259+
} /* GetCurrentAbsoluteTimeUsec() */
260260

261261

262262
void
@@ -344,7 +344,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
344344
{
345345
*tzp = CTimeZone;
346346
tm->tm_gmtoff = CTimeZone;
347-
tm->tm_isdst = -1;
347+
tm->tm_isdst = 0;
348348
tm->tm_zone = NULL;
349349
if (tzn != NULL)
350350
*tzn = NULL;
@@ -366,6 +366,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
366366
}
367367
}
368368
}
369+
else
370+
{
371+
tm->tm_isdst = -1;
372+
}
369373
#elif defined(HAVE_INT_TIMEZONE)
370374
if (tzp != NULL)
371375
{
@@ -376,7 +380,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
376380
if (HasCTZSet)
377381
{
378382
*tzp = CTimeZone;
379-
tm->tm_isdst = -1;
383+
tm->tm_isdst = 0;
380384
if (tzn != NULL)
381385
*tzn = NULL;
382386
}
@@ -397,6 +401,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
397401
}
398402
}
399403
}
404+
else
405+
{
406+
tm->tm_isdst = -1;
407+
}
400408
#endif
401409
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
402410
if (tzp != NULL)
@@ -426,6 +434,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
426434
}
427435
}
428436
}
437+
else
438+
{
439+
tm->tm_isdst = -1;
440+
}
429441
#endif
430442

431443
return;

src/backend/utils/adt/timestamp.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.57 2001/10/18 19:54:59 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.58 2001/10/20 01:02:18 thomas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -374,14 +374,14 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
374374
{
375375
if (typmod != -1)
376376
{
377-
int range = ((typmod >> 16) & 0xFFFF);
377+
int range = ((typmod >> 16) & 0x7FFF);
378378
int precision = (typmod & 0xFFFF);
379379

380-
if (range == 0xFFFF)
380+
if (range == 0x7FFF)
381381
{
382382
/* Do nothing... */
383383
}
384-
if (range == MASK(YEAR))
384+
else if (range == MASK(YEAR))
385385
{
386386
interval->month = ((interval->month / 12) * 12);
387387
interval->time = 0;
@@ -483,7 +483,18 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
483483
IntervalScale = pow(10.0, IntervalTypmod);
484484
}
485485

486-
interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
486+
/* Hmm. For the time field, we can get to a large value
487+
* since we store everything related to an absolute interval
488+
* (e.g. years worth of days) in this one field. So we have
489+
* precision problems doing rint() on this field if the field
490+
* is too large. This resulted in an annoying "...0001" appended
491+
* to the printed result on my Linux box.
492+
* I hate doing an expensive math operation like log10()
493+
* to avoid this, but what else can we do??
494+
* - thomas 2001-10-19
495+
*/
496+
if ((log10(interval->time) + IntervalTypmod) <= 13)
497+
interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
487498
}
488499
}
489500

@@ -671,14 +682,15 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
671682
else
672683
{
673684
*tzp = 0;
674-
tm->tm_isdst = 0;
685+
/* Mark this as *no* time zone available */
686+
tm->tm_isdst = -1;
675687
if (tzn != NULL)
676688
*tzn = NULL;
677689
}
678690
}
679691
else
680692
{
681-
tm->tm_isdst = 0;
693+
tm->tm_isdst = -1;
682694
if (tzn != NULL)
683695
*tzn = NULL;
684696
}

src/test/regress/expected/horology.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
359359
| Tue Feb 10 17:32:01 1998 PST
360360
| Tue Feb 10 17:32:01 1998 PST
361361
| Wed Jun 10 17:32:01 1998 PDT
362-
| Sun Sep 22 11:19:20 2002 PDT
362+
| Sun Sep 22 18:19:20 2002 PDT
363363
| Thu Mar 15 08:14:01 2001 PST
364364
| Thu Mar 15 04:14:02 2001 PST
365365
| Thu Mar 15 02:14:03 2001 PST
@@ -428,7 +428,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
428428
| Sat Feb 10 17:32:01 1996 PST
429429
| Sat Feb 10 17:32:01 1996 PST
430430
| Mon Jun 10 17:32:01 1996 PDT
431-
| Fri Sep 22 11:19:20 2000 PDT
431+
| Fri Sep 22 18:19:20 2000 PDT
432432
| Mon Mar 15 08:14:01 1999 PST
433433
| Mon Mar 15 04:14:02 1999 PST
434434
| Mon Mar 15 02:14:03 1999 PST

0 commit comments

Comments
 (0)