~ubuntu-branches/ubuntu/utopic/postgresql-9.4/utopic-security

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/datetime.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt, CVE-2014-8161
  • Date: 2015-02-06 12:31:46 UTC
  • mfrom: (1.1.5) (7.1.2 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20150206123146-vtmf30jbkm7w16p8
Tags: 9.4.1-0ubuntu0.14.10
* New upstream security/bug fix release (LP: #1418928)
  - Fix buffer overruns in to_char() [CVE-2015-0241]
  - Fix buffer overruns in contrib/pgcrypto [CVE-2015-0243]
  - Fix possible loss of frontend/backend protocol synchronization after an
    error [CVE-2015-0244]
  - Fix information leak via constraint-violation error messages
    [CVE-2014-8161]
  - See release notes for details about other fixes:
    http://www.postgresql.org/about/news/1569/

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
                                   int scale);
51
51
static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
52
52
                                int scale);
 
53
static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp,
 
54
                                                                pg_time_t *tp);
 
55
static int DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
 
56
                                                                          pg_tz *tzp, int *isdst);
 
57
static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
53
58
 
54
59
 
55
60
const int       day_tab[2][13] =
70
75
 *****************************************************************************/
71
76
 
72
77
/*
73
 
 * Definitions for squeezing values into "value"
74
 
 * We set aside a high bit for a sign, and scale the timezone offsets
75
 
 * in minutes by a factor of 15 (so can represent quarter-hour increments).
76
 
 */
77
 
#define ABS_SIGNBIT             ((char) 0200)
78
 
#define VALMASK                 ((char) 0177)
79
 
#define POS(n)                  (n)
80
 
#define NEG(n)                  ((n)|ABS_SIGNBIT)
81
 
#define SIGNEDCHAR(c)   ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
82
 
#define FROMVAL(tp)             (-SIGNEDCHAR((tp)->value) * 15) /* uncompress */
83
 
#define TOVAL(tp, v)    ((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))
84
 
 
85
 
/*
86
78
 * datetktbl holds date/time keywords.
87
79
 *
88
80
 * Note that this table must be strictly alphabetically ordered to allow an
89
81
 * O(ln(N)) search algorithm to be used.
90
82
 *
91
 
 * The token field is NOT guaranteed to be NULL-terminated.
92
 
 *
93
 
 * To keep this table reasonably small, we divide the value for TZ and DTZ
94
 
 * entries by 15 (so they are on 15 minute boundaries) and truncate the token
95
 
 * field at TOKMAXLEN characters.
96
 
 * Formerly, we divided by 10 rather than 15 but there are a few time zones
97
 
 * which are 30 or 45 minutes away from an even hour, most are on an hour
98
 
 * boundary, and none on other boundaries.
99
 
 *
100
 
 * The static table contains no TZ or DTZ entries, rather those are loaded
101
 
 * from configuration files and stored in timezonetktbl, which has the same
102
 
 * format as the static datetktbl.
 
83
 * The token field must be NUL-terminated; we truncate entries to TOKMAXLEN
 
84
 * characters to fit.
 
85
 *
 
86
 * The static table contains no TZ, DTZ, or DYNTZ entries; rather those
 
87
 * are loaded from configuration files and stored in zoneabbrevtbl, whose
 
88
 * abbrevs[] field has the same format as the static datetktbl.
103
89
 */
104
 
static datetkn *timezonetktbl = NULL;
105
 
 
106
 
static int      sztimezonetktbl = 0;
107
 
 
108
90
static const datetkn datetktbl[] = {
109
91
        /* token, type, value */
110
92
        {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
123
105
        {"december", MONTH, 12},
124
106
        {"dow", RESERV, DTK_DOW},       /* day of week */
125
107
        {"doy", RESERV, DTK_DOY},       /* day of year */
126
 
        {"dst", DTZMOD, 6},
 
108
        {"dst", DTZMOD, SECS_PER_HOUR},
127
109
        {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
128
110
        {"feb", MONTH, 2},
129
111
        {"february", MONTH, 2},
185
167
 
186
168
static int      szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
187
169
 
 
170
/*
 
171
 * deltatktbl: same format as datetktbl, but holds keywords used to represent
 
172
 * time units (eg, for intervals, and for EXTRACT).
 
173
 */
188
174
static const datetkn deltatktbl[] = {
189
175
        /* token, type, value */
190
176
        {"@", IGNORE_DTF, 0},           /* postgres relative prefix */
254
240
 
255
241
static int      szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
256
242
 
 
243
static TimeZoneAbbrevTable *zoneabbrevtbl = NULL;
 
244
 
 
245
/* Caches of recent lookup results in the above tables */
 
246
 
257
247
static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
258
248
 
259
249
static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
260
250
 
 
251
static const datetkn *abbrevcache[MAXDATEFIELDS] = {NULL};
 
252
 
261
253
 
262
254
/*
263
255
 * strtoi --- just like strtol, but returns int not long
798
790
        bool            is2digits = FALSE;
799
791
        bool            bc = FALSE;
800
792
        pg_tz      *namedTz = NULL;
 
793
        pg_tz      *abbrevTz = NULL;
 
794
        pg_tz      *valtz;
 
795
        char       *abbrev = NULL;
801
796
        struct pg_tm cur_tm;
802
797
 
803
798
        /*
1194
1189
 
1195
1190
                        case DTK_STRING:
1196
1191
                        case DTK_SPECIAL:
1197
 
                                type = DecodeSpecial(i, field[i], &val);
 
1192
                                /* timezone abbrevs take precedence over built-in tokens */
 
1193
                                type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
 
1194
                                if (type == UNKNOWN_FIELD)
 
1195
                                        type = DecodeSpecial(i, field[i], &val);
1198
1196
                                if (type == IGNORE_DTF)
1199
1197
                                        continue;
1200
1198
 
1286
1284
                                                tm->tm_isdst = 1;
1287
1285
                                                if (tzp == NULL)
1288
1286
                                                        return DTERR_BAD_FORMAT;
1289
 
                                                *tzp += val * MINS_PER_HOUR;
 
1287
                                                *tzp -= val;
1290
1288
                                                break;
1291
1289
 
1292
1290
                                        case DTZ:
1299
1297
                                                tm->tm_isdst = 1;
1300
1298
                                                if (tzp == NULL)
1301
1299
                                                        return DTERR_BAD_FORMAT;
1302
 
                                                *tzp = val * MINS_PER_HOUR;
 
1300
                                                *tzp = -val;
1303
1301
                                                break;
1304
1302
 
1305
1303
                                        case TZ:
1306
1304
                                                tm->tm_isdst = 0;
1307
1305
                                                if (tzp == NULL)
1308
1306
                                                        return DTERR_BAD_FORMAT;
1309
 
                                                *tzp = val * MINS_PER_HOUR;
 
1307
                                                *tzp = -val;
1310
1308
                                                break;
1311
1309
 
1312
 
                                        case IGNORE_DTF:
 
1310
                                        case DYNTZ:
 
1311
                                                tmask |= DTK_M(TZ);
 
1312
                                                if (tzp == NULL)
 
1313
                                                        return DTERR_BAD_FORMAT;
 
1314
                                                /* we'll determine the actual offset later */
 
1315
                                                abbrevTz = valtz;
 
1316
                                                abbrev = field[i];
1313
1317
                                                break;
1314
1318
 
1315
1319
                                        case AMPM:
1419
1423
                        *tzp = DetermineTimeZoneOffset(tm, namedTz);
1420
1424
                }
1421
1425
 
1422
 
                /* timezone not specified? then find local timezone if possible */
 
1426
                /*
 
1427
                 * Likewise, if we had a dynamic timezone abbreviation, resolve it
 
1428
                 * now.
 
1429
                 */
 
1430
                if (abbrevTz != NULL)
 
1431
                {
 
1432
                        /* daylight savings time modifier disallowed with dynamic TZ */
 
1433
                        if (fmask & DTK_M(DTZMOD))
 
1434
                                return DTERR_BAD_FORMAT;
 
1435
 
 
1436
                        *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz);
 
1437
                }
 
1438
 
 
1439
                /* timezone not specified? then use session timezone */
1423
1440
                if (tzp != NULL && !(fmask & DTK_M(TZ)))
1424
1441
                {
1425
1442
                        /*
1439
1456
 
1440
1457
/* DetermineTimeZoneOffset()
1441
1458
 *
1442
 
 * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
1443
 
 * tm_sec fields are set, attempt to determine the applicable time zone
1444
 
 * (ie, regular or daylight-savings time) at that time.  Set the struct pg_tm's
1445
 
 * tm_isdst field accordingly, and return the actual timezone offset.
 
1459
 * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min,
 
1460
 * and tm_sec fields are set, and a zic-style time zone definition, determine
 
1461
 * the applicable GMT offset and daylight-savings status at that time.
 
1462
 * Set the struct pg_tm's tm_isdst field accordingly, and return the GMT
 
1463
 * offset as the function result.
 
1464
 *
 
1465
 * Note: if the date is out of the range we can deal with, we return zero
 
1466
 * as the GMT offset and set tm_isdst = 0.  We don't throw an error here,
 
1467
 * though probably some higher-level code will.
 
1468
 */
 
1469
int
 
1470
DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp)
 
1471
{
 
1472
        pg_time_t       t;
 
1473
 
 
1474
        return DetermineTimeZoneOffsetInternal(tm, tzp, &t);
 
1475
}
 
1476
 
 
1477
 
 
1478
/* DetermineTimeZoneOffsetInternal()
 
1479
 *
 
1480
 * As above, but also return the actual UTC time imputed to the date/time
 
1481
 * into *tp.
 
1482
 *
 
1483
 * In event of an out-of-range date, we punt by returning zero into *tp.
 
1484
 * This is okay for the immediate callers but is a good reason for not
 
1485
 * exposing this worker function globally.
1446
1486
 *
1447
1487
 * Note: it might seem that we should use mktime() for this, but bitter
1448
1488
 * experience teaches otherwise.  This code is much faster than most versions
1449
1489
 * of mktime(), anyway.
1450
1490
 */
1451
 
int
1452
 
DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp)
 
1491
static int
 
1492
DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp)
1453
1493
{
1454
1494
        int                     date,
1455
1495
                                sec;
1468
1508
        /*
1469
1509
         * First, generate the pg_time_t value corresponding to the given
1470
1510
         * y/m/d/h/m/s taken as GMT time.  If this overflows, punt and decide the
1471
 
         * timezone is GMT.  (We only need to worry about overflow on machines
1472
 
         * where pg_time_t is 32 bits.)
 
1511
         * timezone is GMT.  (For a valid Julian date, integer overflow should be
 
1512
         * impossible with 64-bit pg_time_t, but let's check for safety.)
1473
1513
         */
1474
1514
        if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1475
1515
                goto overflow;
1506
1546
        {
1507
1547
                /* Non-DST zone, life is simple */
1508
1548
                tm->tm_isdst = before_isdst;
 
1549
                *tp = mytime - before_gmtoff;
1509
1550
                return -(int) before_gmtoff;
1510
1551
        }
1511
1552
 
1526
1567
                goto overflow;
1527
1568
 
1528
1569
        /*
1529
 
         * If both before or both after the boundary time, we know what to do
 
1570
         * If both before or both after the boundary time, we know what to do. The
 
1571
         * boundary time itself is considered to be after the transition, which
 
1572
         * means we can accept aftertime == boundary in the second case.
1530
1573
         */
1531
 
        if (beforetime <= boundary && aftertime < boundary)
 
1574
        if (beforetime < boundary && aftertime < boundary)
1532
1575
        {
1533
1576
                tm->tm_isdst = before_isdst;
 
1577
                *tp = beforetime;
1534
1578
                return -(int) before_gmtoff;
1535
1579
        }
1536
1580
        if (beforetime > boundary && aftertime >= boundary)
1537
1581
        {
1538
1582
                tm->tm_isdst = after_isdst;
 
1583
                *tp = aftertime;
1539
1584
                return -(int) after_gmtoff;
1540
1585
        }
1541
1586
 
1542
1587
        /*
1543
 
         * It's an invalid or ambiguous time due to timezone transition. Prefer
1544
 
         * the standard-time interpretation.
 
1588
         * It's an invalid or ambiguous time due to timezone transition.  In a
 
1589
         * spring-forward transition, prefer the "before" interpretation; in a
 
1590
         * fall-back transition, prefer "after".  (We used to define and implement
 
1591
         * this test as "prefer the standard-time interpretation", but that rule
 
1592
         * does not help to resolve the behavior when both times are reported as
 
1593
         * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
1545
1594
         */
1546
 
        if (after_isdst == 0)
 
1595
        if (beforetime > aftertime)
1547
1596
        {
1548
 
                tm->tm_isdst = after_isdst;
1549
 
                return -(int) after_gmtoff;
 
1597
                tm->tm_isdst = before_isdst;
 
1598
                *tp = beforetime;
 
1599
                return -(int) before_gmtoff;
1550
1600
        }
1551
 
        tm->tm_isdst = before_isdst;
1552
 
        return -(int) before_gmtoff;
 
1601
        tm->tm_isdst = after_isdst;
 
1602
        *tp = aftertime;
 
1603
        return -(int) after_gmtoff;
1553
1604
 
1554
1605
overflow:
1555
1606
        /* Given date is out of range, so assume UTC */
1556
1607
        tm->tm_isdst = 0;
 
1608
        *tp = 0;
1557
1609
        return 0;
1558
1610
}
1559
1611
 
1560
1612
 
 
1613
/* DetermineTimeZoneAbbrevOffset()
 
1614
 *
 
1615
 * Determine the GMT offset and DST flag to be attributed to a dynamic
 
1616
 * time zone abbreviation, that is one whose meaning has changed over time.
 
1617
 * *tm contains the local time at which the meaning should be determined,
 
1618
 * and tm->tm_isdst receives the DST flag.
 
1619
 *
 
1620
 * This differs from the behavior of DetermineTimeZoneOffset() in that a
 
1621
 * standard-time or daylight-time abbreviation forces use of the corresponding
 
1622
 * GMT offset even when the zone was then in DS or standard time respectively.
 
1623
 */
 
1624
int
 
1625
DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp)
 
1626
{
 
1627
        pg_time_t       t;
 
1628
 
 
1629
        /*
 
1630
         * Compute the UTC time we want to probe at.  (In event of overflow, we'll
 
1631
         * probe at the epoch, which is a bit random but probably doesn't matter.)
 
1632
         */
 
1633
        (void) DetermineTimeZoneOffsetInternal(tm, tzp, &t);
 
1634
 
 
1635
        return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, &tm->tm_isdst);
 
1636
}
 
1637
 
 
1638
 
 
1639
/* DetermineTimeZoneAbbrevOffsetTS()
 
1640
 *
 
1641
 * As above but the probe time is specified as a TimestampTz (hence, UTC time),
 
1642
 * and DST status is returned into *isdst rather than into tm->tm_isdst.
 
1643
 */
 
1644
int
 
1645
DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr,
 
1646
                                                                pg_tz *tzp, int *isdst)
 
1647
{
 
1648
        pg_time_t       t = timestamptz_to_time_t(ts);
 
1649
 
 
1650
        return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, isdst);
 
1651
}
 
1652
 
 
1653
 
 
1654
/* DetermineTimeZoneAbbrevOffsetInternal()
 
1655
 *
 
1656
 * Workhorse for above two functions: work from a pg_time_t probe instant.
 
1657
 * DST status is returned into *isdst.
 
1658
 */
 
1659
static int
 
1660
DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr,
 
1661
                                                                          pg_tz *tzp, int *isdst)
 
1662
{
 
1663
        char            upabbr[TZ_STRLEN_MAX + 1];
 
1664
        unsigned char *p;
 
1665
        long int        gmtoff;
 
1666
 
 
1667
        /* We need to force the abbrev to upper case */
 
1668
        strlcpy(upabbr, abbr, sizeof(upabbr));
 
1669
        for (p = (unsigned char *) upabbr; *p; p++)
 
1670
                *p = pg_toupper(*p);
 
1671
 
 
1672
        /* Look up the abbrev's meaning at this time in this zone */
 
1673
        if (!pg_interpret_timezone_abbrev(upabbr,
 
1674
                                                                          &t,
 
1675
                                                                          &gmtoff,
 
1676
                                                                          isdst,
 
1677
                                                                          tzp))
 
1678
                ereport(ERROR,
 
1679
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
 
1680
                                 errmsg("time zone abbreviation \"%s\" is not used in time zone \"%s\"",
 
1681
                                                abbr, pg_get_timezone_name(tzp))));
 
1682
 
 
1683
        /* Change sign to agree with DetermineTimeZoneOffset() */
 
1684
        return (int) -gmtoff;
 
1685
}
 
1686
 
 
1687
 
1561
1688
/* DecodeTimeOnly()
1562
1689
 * Interpret parsed string as time fields only.
1563
1690
 * Returns 0 if successful, DTERR code if bogus input detected.
1586
1713
        bool            bc = FALSE;
1587
1714
        int                     mer = HR24;
1588
1715
        pg_tz      *namedTz = NULL;
 
1716
        pg_tz      *abbrevTz = NULL;
 
1717
        char       *abbrev = NULL;
 
1718
        pg_tz      *valtz;
1589
1719
 
1590
1720
        *dtype = DTK_TIME;
1591
1721
        tm->tm_hour = 0;
1930
2060
 
1931
2061
                        case DTK_STRING:
1932
2062
                        case DTK_SPECIAL:
1933
 
                                type = DecodeSpecial(i, field[i], &val);
 
2063
                                /* timezone abbrevs take precedence over built-in tokens */
 
2064
                                type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
 
2065
                                if (type == UNKNOWN_FIELD)
 
2066
                                        type = DecodeSpecial(i, field[i], &val);
1934
2067
                                if (type == IGNORE_DTF)
1935
2068
                                        continue;
1936
2069
 
1978
2111
                                                tm->tm_isdst = 1;
1979
2112
                                                if (tzp == NULL)
1980
2113
                                                        return DTERR_BAD_FORMAT;
1981
 
                                                *tzp += val * MINS_PER_HOUR;
 
2114
                                                *tzp -= val;
1982
2115
                                                break;
1983
2116
 
1984
2117
                                        case DTZ:
1991
2124
                                                tm->tm_isdst = 1;
1992
2125
                                                if (tzp == NULL)
1993
2126
                                                        return DTERR_BAD_FORMAT;
1994
 
                                                *tzp = val * MINS_PER_HOUR;
 
2127
                                                *tzp = -val;
1995
2128
                                                ftype[i] = DTK_TZ;
1996
2129
                                                break;
1997
2130
 
1999
2132
                                                tm->tm_isdst = 0;
2000
2133
                                                if (tzp == NULL)
2001
2134
                                                        return DTERR_BAD_FORMAT;
2002
 
                                                *tzp = val * MINS_PER_HOUR;
 
2135
                                                *tzp = -val;
2003
2136
                                                ftype[i] = DTK_TZ;
2004
2137
                                                break;
2005
2138
 
2006
 
                                        case IGNORE_DTF:
 
2139
                                        case DYNTZ:
 
2140
                                                tmask |= DTK_M(TZ);
 
2141
                                                if (tzp == NULL)
 
2142
                                                        return DTERR_BAD_FORMAT;
 
2143
                                                /* we'll determine the actual offset later */
 
2144
                                                abbrevTz = valtz;
 
2145
                                                abbrev = field[i];
 
2146
                                                ftype[i] = DTK_TZ;
2007
2147
                                                break;
2008
2148
 
2009
2149
                                        case AMPM:
2123
2263
                }
2124
2264
        }
2125
2265
 
2126
 
        /* timezone not specified? then find local timezone if possible */
 
2266
        /*
 
2267
         * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
 
2268
         */
 
2269
        if (abbrevTz != NULL)
 
2270
        {
 
2271
                struct pg_tm tt,
 
2272
                                   *tmp = &tt;
 
2273
 
 
2274
                /*
 
2275
                 * daylight savings time modifier but no standard timezone? then error
 
2276
                 */
 
2277
                if (fmask & DTK_M(DTZMOD))
 
2278
                        return DTERR_BAD_FORMAT;
 
2279
 
 
2280
                if ((fmask & DTK_DATE_M) == 0)
 
2281
                        GetCurrentDateTime(tmp);
 
2282
                else
 
2283
                {
 
2284
                        tmp->tm_year = tm->tm_year;
 
2285
                        tmp->tm_mon = tm->tm_mon;
 
2286
                        tmp->tm_mday = tm->tm_mday;
 
2287
                }
 
2288
                tmp->tm_hour = tm->tm_hour;
 
2289
                tmp->tm_min = tm->tm_min;
 
2290
                tmp->tm_sec = tm->tm_sec;
 
2291
                *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
 
2292
                tm->tm_isdst = tmp->tm_isdst;
 
2293
        }
 
2294
 
 
2295
        /* timezone not specified? then use session timezone */
2127
2296
        if (tzp != NULL && !(fmask & DTK_M(TZ)))
2128
2297
        {
2129
2298
                struct pg_tm tt,
2710
2879
 * Interpret string as a numeric timezone.
2711
2880
 *
2712
2881
 * Return 0 if okay (and set *tzp), a DTERR code if not okay.
2713
 
 *
2714
 
 * NB: this must *not* ereport on failure; see commands/variable.c.
2715
2882
 */
2716
2883
int
2717
2884
DecodeTimezone(char *str, int *tzp)
2776
2943
        return 0;
2777
2944
}
2778
2945
 
 
2946
 
 
2947
/* DecodeTimezoneAbbrev()
 
2948
 * Interpret string as a timezone abbreviation, if possible.
 
2949
 *
 
2950
 * Returns an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
 
2951
 * string is not any known abbreviation.  On success, set *offset and *tz to
 
2952
 * represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
 
2953
 * Note that full timezone names (such as America/New_York) are not handled
 
2954
 * here, mostly for historical reasons.
 
2955
 *
 
2956
 * Given string must be lowercased already.
 
2957
 *
 
2958
 * Implement a cache lookup since it is likely that dates
 
2959
 *      will be related in format.
 
2960
 */
 
2961
int
 
2962
DecodeTimezoneAbbrev(int field, char *lowtoken,
 
2963
                                         int *offset, pg_tz **tz)
 
2964
{
 
2965
        int                     type;
 
2966
        const datetkn *tp;
 
2967
 
 
2968
        tp = abbrevcache[field];
 
2969
        /* use strncmp so that we match truncated tokens */
 
2970
        if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
 
2971
        {
 
2972
                if (zoneabbrevtbl)
 
2973
                        tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
 
2974
                                                         zoneabbrevtbl->numabbrevs);
 
2975
                else
 
2976
                        tp = NULL;
 
2977
        }
 
2978
        if (tp == NULL)
 
2979
        {
 
2980
                type = UNKNOWN_FIELD;
 
2981
                *offset = 0;
 
2982
                *tz = NULL;
 
2983
        }
 
2984
        else
 
2985
        {
 
2986
                abbrevcache[field] = tp;
 
2987
                type = tp->type;
 
2988
                if (type == DYNTZ)
 
2989
                {
 
2990
                        *offset = 0;
 
2991
                        *tz = FetchDynamicTimeZone(zoneabbrevtbl, tp);
 
2992
                }
 
2993
                else
 
2994
                {
 
2995
                        *offset = tp->value;
 
2996
                        *tz = NULL;
 
2997
                }
 
2998
        }
 
2999
 
 
3000
        return type;
 
3001
}
 
3002
 
 
3003
 
2779
3004
/* DecodeSpecial()
2780
3005
 * Decode text string using lookup table.
2781
3006
 *
 
3007
 * Recognizes the keywords listed in datetktbl.
 
3008
 * Note: at one time this would also recognize timezone abbreviations,
 
3009
 * but no more; use DecodeTimezoneAbbrev for that.
 
3010
 *
 
3011
 * Given string must be lowercased already.
 
3012
 *
2782
3013
 * Implement a cache lookup since it is likely that dates
2783
3014
 *      will be related in format.
2784
 
 *
2785
 
 * NB: this must *not* ereport on failure;
2786
 
 * see commands/variable.c.
2787
3015
 */
2788
3016
int
2789
3017
DecodeSpecial(int field, char *lowtoken, int *val)
2792
3020
        const datetkn *tp;
2793
3021
 
2794
3022
        tp = datecache[field];
 
3023
        /* use strncmp so that we match truncated tokens */
2795
3024
        if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
2796
3025
        {
2797
 
                tp = datebsearch(lowtoken, timezonetktbl, sztimezonetktbl);
2798
 
                if (tp == NULL)
2799
 
                        tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
 
3026
                tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
2800
3027
        }
2801
3028
        if (tp == NULL)
2802
3029
        {
2807
3034
        {
2808
3035
                datecache[field] = tp;
2809
3036
                type = tp->type;
2810
 
                switch (type)
2811
 
                {
2812
 
                        case TZ:
2813
 
                        case DTZ:
2814
 
                        case DTZMOD:
2815
 
                                *val = FROMVAL(tp);
2816
 
                                break;
2817
 
 
2818
 
                        default:
2819
 
                                *val = tp->value;
2820
 
                                break;
2821
 
                }
 
3037
                *val = tp->value;
2822
3038
        }
2823
3039
 
2824
3040
        return type;
3494
3710
 
3495
3711
/* DecodeUnits()
3496
3712
 * Decode text string using lookup table.
3497
 
 * This routine supports time interval decoding
3498
 
 * (hence, it need not recognize timezone names).
 
3713
 *
 
3714
 * This routine recognizes keywords associated with time interval units.
 
3715
 *
 
3716
 * Given string must be lowercased already.
 
3717
 *
 
3718
 * Implement a cache lookup since it is likely that dates
 
3719
 *      will be related in format.
3499
3720
 */
3500
3721
int
3501
3722
DecodeUnits(int field, char *lowtoken, int *val)
3504
3725
        const datetkn *tp;
3505
3726
 
3506
3727
        tp = deltacache[field];
 
3728
        /* use strncmp so that we match truncated tokens */
3507
3729
        if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3508
3730
        {
3509
3731
                tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3517
3739
        {
3518
3740
                deltacache[field] = tp;
3519
3741
                type = tp->type;
3520
 
                if (type == TZ || type == DTZ)
3521
 
                        *val = FROMVAL(tp);
3522
 
                else
3523
 
                        *val = tp->value;
 
3742
                *val = tp->value;
3524
3743
        }
3525
3744
 
3526
3745
        return type;
3593
3812
                while (last >= base)
3594
3813
                {
3595
3814
                        position = base + ((last - base) >> 1);
3596
 
                        result = key[0] - position->token[0];
 
3815
                        /* precheck the first character for a bit of extra speed */
 
3816
                        result = (int) key[0] - (int) position->token[0];
3597
3817
                        if (result == 0)
3598
3818
                        {
 
3819
                                /* use strncmp so that we match truncated tokens */
3599
3820
                                result = strncmp(key, position->token, TOKMAXLEN);
3600
3821
                                if (result == 0)
3601
3822
                                        return position;
4142
4363
        bool            ok = true;
4143
4364
        int                     i;
4144
4365
 
4145
 
        for (i = 1; i < nel; i++)
 
4366
        for (i = 0; i < nel; i++)
4146
4367
        {
4147
 
                if (strncmp(base[i - 1].token, base[i].token, TOKMAXLEN) >= 0)
 
4368
                /* check for token strings that don't fit */
 
4369
                if (strlen(base[i].token) > TOKMAXLEN)
4148
4370
                {
4149
4371
                        /* %.*s is safe since all our tokens are ASCII */
4150
 
                        elog(LOG, "ordering error in %s table: \"%.*s\" >= \"%.*s\"",
4151
 
                                 tablename,
4152
 
                                 TOKMAXLEN, base[i - 1].token,
4153
 
                                 TOKMAXLEN, base[i].token);
 
4372
                        elog(LOG, "token too long in %s table: \"%.*s\"",
 
4373
                                 tablename,
 
4374
                                 TOKMAXLEN + 1, base[i].token);
 
4375
                        ok = false;
 
4376
                        break;                          /* don't risk applying strcmp */
 
4377
                }
 
4378
                /* check for out of order */
 
4379
                if (i > 0 &&
 
4380
                        strcmp(base[i - 1].token, base[i].token) >= 0)
 
4381
                {
 
4382
                        elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
 
4383
                                 tablename,
 
4384
                                 base[i - 1].token,
 
4385
                                 base[i].token);
4154
4386
                        ok = false;
4155
4387
                }
4156
4388
        }
4208
4440
/*
4209
4441
 * This function gets called during timezone config file load or reload
4210
4442
 * to create the final array of timezone tokens.  The argument array
4211
 
 * is already sorted in name order.  The data is converted to datetkn
4212
 
 * format and installed in *tbl, which must be allocated by the caller.
 
4443
 * is already sorted in name order.
 
4444
 *
 
4445
 * The result is a TimeZoneAbbrevTable (which must be a single malloc'd chunk)
 
4446
 * or NULL on malloc failure.  No other error conditions are defined.
4213
4447
 */
4214
 
void
4215
 
ConvertTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl,
4216
 
                                           struct tzEntry *abbrevs, int n)
 
4448
TimeZoneAbbrevTable *
 
4449
ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
4217
4450
{
4218
 
        datetkn    *newtbl = tbl->abbrevs;
 
4451
        TimeZoneAbbrevTable *tbl;
 
4452
        Size            tbl_size;
4219
4453
        int                     i;
4220
4454
 
 
4455
        /* Space for fixed fields and datetkn array */
 
4456
        tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
 
4457
                n * sizeof(datetkn);
 
4458
        tbl_size = MAXALIGN(tbl_size);
 
4459
        /* Count up space for dynamic abbreviations */
 
4460
        for (i = 0; i < n; i++)
 
4461
        {
 
4462
                struct tzEntry *abbr = abbrevs + i;
 
4463
 
 
4464
                if (abbr->zone != NULL)
 
4465
                {
 
4466
                        Size            dsize;
 
4467
 
 
4468
                        dsize = offsetof(DynamicZoneAbbrev, zone) +
 
4469
                                strlen(abbr->zone) + 1;
 
4470
                        tbl_size += MAXALIGN(dsize);
 
4471
                }
 
4472
        }
 
4473
 
 
4474
        /* Alloc the result ... */
 
4475
        tbl = malloc(tbl_size);
 
4476
        if (!tbl)
 
4477
                return NULL;
 
4478
 
 
4479
        /* ... and fill it in */
 
4480
        tbl->tblsize = tbl_size;
4221
4481
        tbl->numabbrevs = n;
 
4482
        /* in this loop, tbl_size reprises the space calculation above */
 
4483
        tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
 
4484
                n * sizeof(datetkn);
 
4485
        tbl_size = MAXALIGN(tbl_size);
4222
4486
        for (i = 0; i < n; i++)
4223
4487
        {
4224
 
                /* do NOT use strlcpy here; token field need not be null-terminated */
4225
 
                strncpy(newtbl[i].token, abbrevs[i].abbrev, TOKMAXLEN);
4226
 
                newtbl[i].type = abbrevs[i].is_dst ? DTZ : TZ;
4227
 
                TOVAL(&newtbl[i], abbrevs[i].offset / MINS_PER_HOUR);
 
4488
                struct tzEntry *abbr = abbrevs + i;
 
4489
                datetkn    *dtoken = tbl->abbrevs + i;
 
4490
 
 
4491
                /* use strlcpy to truncate name if necessary */
 
4492
                strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
 
4493
                if (abbr->zone != NULL)
 
4494
                {
 
4495
                        /* Allocate a DynamicZoneAbbrev for this abbreviation */
 
4496
                        DynamicZoneAbbrev *dtza;
 
4497
                        Size            dsize;
 
4498
 
 
4499
                        dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
 
4500
                        dtza->tz = NULL;
 
4501
                        strcpy(dtza->zone, abbr->zone);
 
4502
 
 
4503
                        dtoken->type = DYNTZ;
 
4504
                        /* value is offset from table start to DynamicZoneAbbrev */
 
4505
                        dtoken->value = (int32) tbl_size;
 
4506
 
 
4507
                        dsize = offsetof(DynamicZoneAbbrev, zone) +
 
4508
                                strlen(abbr->zone) + 1;
 
4509
                        tbl_size += MAXALIGN(dsize);
 
4510
                }
 
4511
                else
 
4512
                {
 
4513
                        dtoken->type = abbr->is_dst ? DTZ : TZ;
 
4514
                        dtoken->value = abbr->offset;
 
4515
                }
4228
4516
        }
4229
4517
 
 
4518
        /* Assert the two loops above agreed on size calculations */
 
4519
        Assert(tbl->tblsize == tbl_size);
 
4520
 
4230
4521
        /* Check the ordering, if testing */
4231
 
        Assert(CheckDateTokenTable("timezone offset", newtbl, n));
 
4522
        Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
 
4523
 
 
4524
        return tbl;
4232
4525
}
4233
4526
 
4234
4527
/*
4239
4532
void
4240
4533
InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
4241
4534
{
4242
 
        int                     i;
4243
 
 
4244
 
        timezonetktbl = tbl->abbrevs;
4245
 
        sztimezonetktbl = tbl->numabbrevs;
4246
 
 
4247
 
        /* clear date cache in case it contains any stale timezone names */
4248
 
        for (i = 0; i < MAXDATEFIELDS; i++)
4249
 
                datecache[i] = NULL;
4250
 
}
 
4535
        zoneabbrevtbl = tbl;
 
4536
        /* reset abbrevcache, which may contain pointers into old table */
 
4537
        memset(abbrevcache, 0, sizeof(abbrevcache));
 
4538
}
 
4539
 
 
4540
/*
 
4541
 * Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
 
4542
 */
 
4543
static pg_tz *
 
4544
FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
 
4545
{
 
4546
        DynamicZoneAbbrev *dtza;
 
4547
 
 
4548
        /* Just some sanity checks to prevent indexing off into nowhere */
 
4549
        Assert(tp->type == DYNTZ);
 
4550
        Assert(tp->value > 0 && tp->value < tbl->tblsize);
 
4551
 
 
4552
        dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
 
4553
 
 
4554
        /* Look up the underlying zone if we haven't already */
 
4555
        if (dtza->tz == NULL)
 
4556
        {
 
4557
                dtza->tz = pg_tzset(dtza->zone);
 
4558
 
 
4559
                /*
 
4560
                 * Ideally we'd let the caller ereport instead of doing it here, but
 
4561
                 * then there is no way to report the bad time zone name.
 
4562
                 */
 
4563
                if (dtza->tz == NULL)
 
4564
                        ereport(ERROR,
 
4565
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
 
4566
                                         errmsg("time zone \"%s\" not recognized",
 
4567
                                                        dtza->zone),
 
4568
                                         errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
 
4569
                                                           tp->token)));
 
4570
        }
 
4571
        return dtza->tz;
 
4572
}
 
4573
 
4251
4574
 
4252
4575
/*
4253
4576
 * This set-returning function reads all the available time zone abbreviations
4262
4585
        HeapTuple       tuple;
4263
4586
        Datum           values[3];
4264
4587
        bool            nulls[3];
 
4588
        const datetkn *tp;
4265
4589
        char            buffer[TOKMAXLEN + 1];
 
4590
        int                     gmtoffset;
 
4591
        bool            is_dst;
4266
4592
        unsigned char *p;
4267
4593
        struct pg_tm tm;
4268
4594
        Interval   *resInterval;
4306
4632
        funcctx = SRF_PERCALL_SETUP();
4307
4633
        pindex = (int *) funcctx->user_fctx;
4308
4634
 
4309
 
        if (*pindex >= sztimezonetktbl)
 
4635
        if (zoneabbrevtbl == NULL ||
 
4636
                *pindex >= zoneabbrevtbl->numabbrevs)
4310
4637
                SRF_RETURN_DONE(funcctx);
4311
4638
 
 
4639
        tp = zoneabbrevtbl->abbrevs + *pindex;
 
4640
 
 
4641
        switch (tp->type)
 
4642
        {
 
4643
                case TZ:
 
4644
                        gmtoffset = tp->value;
 
4645
                        is_dst = false;
 
4646
                        break;
 
4647
                case DTZ:
 
4648
                        gmtoffset = tp->value;
 
4649
                        is_dst = true;
 
4650
                        break;
 
4651
                case DYNTZ:
 
4652
                        {
 
4653
                                /* Determine the current meaning of the abbrev */
 
4654
                                pg_tz      *tzp;
 
4655
                                TimestampTz now;
 
4656
                                int                     isdst;
 
4657
 
 
4658
                                tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp);
 
4659
                                now = GetCurrentTransactionStartTimestamp();
 
4660
                                gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now,
 
4661
                                                                                                                         tp->token,
 
4662
                                                                                                                         tzp,
 
4663
                                                                                                                         &isdst);
 
4664
                                is_dst = (bool) isdst;
 
4665
                                break;
 
4666
                        }
 
4667
                default:
 
4668
                        elog(ERROR, "unrecognized timezone type %d", (int) tp->type);
 
4669
                        gmtoffset = 0;          /* keep compiler quiet */
 
4670
                        is_dst = false;
 
4671
                        break;
 
4672
        }
 
4673
 
4312
4674
        MemSet(nulls, 0, sizeof(nulls));
4313
4675
 
4314
4676
        /*
4315
4677
         * Convert name to text, using upcasing conversion that is the inverse of
4316
4678
         * what ParseDateTime() uses.
4317
4679
         */
4318
 
        strncpy(buffer, timezonetktbl[*pindex].token, TOKMAXLEN);
4319
 
        buffer[TOKMAXLEN] = '\0';       /* may not be null-terminated */
 
4680
        strlcpy(buffer, tp->token, sizeof(buffer));
4320
4681
        for (p = (unsigned char *) buffer; *p; p++)
4321
4682
                *p = pg_toupper(*p);
4322
4683
 
4323
4684
        values[0] = CStringGetTextDatum(buffer);
4324
4685
 
 
4686
        /* Convert offset (in seconds) to an interval */
4325
4687
        MemSet(&tm, 0, sizeof(struct pg_tm));
4326
 
        tm.tm_min = (-1) * FROMVAL(&timezonetktbl[*pindex]);
 
4688
        tm.tm_sec = gmtoffset;
4327
4689
        resInterval = (Interval *) palloc(sizeof(Interval));
4328
4690
        tm2interval(&tm, 0, resInterval);
4329
4691
        values[1] = IntervalPGetDatum(resInterval);
4330
4692
 
4331
 
        Assert(timezonetktbl[*pindex].type == DTZ ||
4332
 
                   timezonetktbl[*pindex].type == TZ);
4333
 
        values[2] = BoolGetDatum(timezonetktbl[*pindex].type == DTZ);
 
4693
        values[2] = BoolGetDatum(is_dst);
4334
4694
 
4335
4695
        (*pindex)++;
4336
4696