]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/datetime.c
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / backend / utils / adt / datetime.c
index 8375b93c39777979a9d437ef53afdcd71e756e34..e38bd930543f9e1a1462d6b330e7e1637660884b 100644 (file)
@@ -3,7 +3,7 @@
  * datetime.c
  *       Support functions for date/time types.
  *
- * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
 #include "postgres.h"
 
 #include <ctype.h>
-#include <float.h>
 #include <limits.h>
 #include <math.h>
 
 #include "access/htup_details.h"
 #include "access/xact.h"
 #include "catalog/pg_type.h"
+#include "common/string.h"
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/tzparser.h"
 
 
-static int DecodeNumber(int flen, char *field, bool haveTextMonth,
-                        int fmask, int *tmask,
-                        struct pg_tm *tm, fsec_t *fsec, bool *is2digits);
-static int DecodeNumberField(int len, char *str,
-                                 int fmask, int *tmask,
-                                 struct pg_tm *tm, fsec_t *fsec, bool *is2digits);
-static int DecodeTime(char *str, int fmask, int range,
-                  int *tmask, struct pg_tm *tm, fsec_t *fsec);
+static int     DecodeNumber(int flen, char *field, bool haveTextMonth,
+                                                int fmask, int *tmask,
+                                                struct pg_tm *tm, fsec_t *fsec, bool *is2digits);
+static int     DecodeNumberField(int len, char *str,
+                                                         int fmask, int *tmask,
+                                                         struct pg_tm *tm, fsec_t *fsec, bool *is2digits);
+static int     DecodeTime(char *str, int fmask, int range,
+                                          int *tmask, struct pg_tm *tm, fsec_t *fsec);
 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
-static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
-                  struct pg_tm *tm);
+static int     DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
+                                          struct pg_tm *tm);
 static char *AppendSeconds(char *cp, int sec, fsec_t fsec,
-                         int precision, bool fillzeros);
+                                                  int precision, bool fillzeros);
 static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec,
-                                  int scale);
+                                                          int scale);
 static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec,
-                               int scale);
-static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp,
-                                                               pg_time_t *tp);
+                                                       int scale);
+static int     DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp,
+                                                                                       pg_time_t *tp);
 static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t,
-                                                                         const char *abbr, pg_tz *tzp,
-                                                                         int *offset, int *isdst);
+                                                                                                 const char *abbr, pg_tz *tzp,
+                                                                                                 int *offset, int *isdst);
 static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
 
 
@@ -99,7 +99,6 @@ static const datetkn datetktbl[] = {
        {"aug", MONTH, 8},
        {"august", MONTH, 8},
        {DB_C, ADBC, BC},                       /* "bc" for years <= 0 */
-       {DCURRENT, RESERV, DTK_CURRENT},        /* "current" is always now */
        {"d", UNITS, DTK_DAY},          /* "day of month" for ISO input */
        {"dec", MONTH, 12},
        {"december", MONTH, 12},
@@ -113,7 +112,6 @@ static const datetkn datetktbl[] = {
        {"friday", DOW, 5},
        {"h", UNITS, DTK_HOUR},         /* "hour" */
        {LATE, RESERV, DTK_LATE},       /* "infinity" reserved for "late time" */
-       {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */
        {"isodow", UNITS, DTK_ISODOW},  /* ISO day of week, Sunday == 7 */
        {"isoyear", UNITS, DTK_ISOYEAR},        /* year in terms of the ISO week date */
        {"j", UNITS, DTK_JULIAN},
@@ -157,7 +155,6 @@ static const datetkn datetktbl[] = {
        {"tue", DOW, 2},
        {"tues", DOW, 2},
        {"tuesday", DOW, 2},
-       {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
        {"wed", DOW, 3},
        {"wednesday", DOW, 3},
        {"weds", DOW, 3},
@@ -165,7 +162,7 @@ static const datetkn datetktbl[] = {
        {YESTERDAY, RESERV, DTK_YESTERDAY}      /* yesterday midnight */
 };
 
-static int     szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
+static const int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
 
 /*
  * deltatktbl: same format as datetktbl, but holds keywords used to represent
@@ -191,7 +188,6 @@ static const datetkn deltatktbl[] = {
        {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
        {"hr", UNITS, DTK_HOUR},        /* "hour" relative */
        {"hrs", UNITS, DTK_HOUR},       /* "hours" relative */
-       {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */
        {"m", UNITS, DTK_MINUTE},       /* "minute" relative */
        {"microsecon", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
        {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
@@ -222,7 +218,6 @@ static const datetkn deltatktbl[] = {
        {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
        {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
        {"timezone_m", UNITS, DTK_TZ_MINUTE},   /* timezone minutes units */
-       {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
        {"us", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
        {"usec", UNITS, DTK_MICROSEC},  /* "microsecond" relative */
        {DMICROSEC, UNITS, DTK_MICROSEC},       /* "microsecond" relative */
@@ -238,7 +233,7 @@ static const datetkn deltatktbl[] = {
        {"yrs", UNITS, DTK_YEAR}        /* "years" relative */
 };
 
-static int     szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
+static const int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
 
 static TimeZoneAbbrevTable *zoneabbrevtbl = NULL;
 
@@ -251,23 +246,6 @@ static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
 static const datetkn *abbrevcache[MAXDATEFIELDS] = {NULL};
 
 
-/*
- * strtoint --- just like strtol, but returns int not long
- */
-static int
-strtoint(const char *nptr, char **endptr, int base)
-{
-       long            val;
-
-       val = strtol(nptr, endptr, base);
-#ifdef HAVE_LONG_INT_64
-       if (val != (long) ((int32) val))
-               errno = ERANGE;
-#endif
-       return (int) val;
-}
-
-
 /*
  * Calendar time to Julian date conversions.
  * Julian date is commonly used in astronomical applications,
@@ -1161,8 +1139,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                         * Is this a YMD or HMS specification, or a year number?
                                         * YMD and HMS are required to be six digits or more, so
                                         * if it is 5 digits, it is a year.  If it is six or more
-                                        * more digits, we assume it is YMD or HMS unless no date
-                                        * and no time values have been specified.  This forces 6+
+                                        * digits, we assume it is YMD or HMS unless no date and
+                                        * no time values have been specified.  This forces 6+
                                         * digit years to be at the end of the string, or to use
                                         * the ISO date specification.
                                         */
@@ -1203,14 +1181,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                        case RESERV:
                                                switch (val)
                                                {
-                                                       case DTK_CURRENT:
-                                                               ereport(ERROR,
-                                                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                                                errmsg("date/time value \"current\" is no longer supported")));
-
-                                                               return DTERR_BAD_FORMAT;
-                                                               break;
-
                                                        case DTK_NOW:
                                                                tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
                                                                *dtype = DTK_DATE;
@@ -1591,7 +1561,10 @@ DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
         * fall-back transition, prefer "after".  (We used to define and implement
         * this test as "prefer the standard-time interpretation", but that rule
         * does not help to resolve the behavior when both times are reported as
-        * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
+        * standard time; which does happen, eg Europe/Moscow in Oct 2014.  Also,
+        * in some zones such as Europe/Dublin, there is widespread confusion
+        * about which time offset is "standard" time, so it's fortunate that our
+        * behavior doesn't depend on that.)
         */
        if (beforetime > aftertime)
        {
@@ -1882,7 +1855,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
 
                                /*
                                 * Was this an "ISO time" with embedded field labels? An
-                                * example is "h04m05s06" - thomas 2001-02-04
+                                * example is "h04mm05s06" - thomas 2001-02-04
                                 */
                                if (ptype != 0)
                                {
@@ -2111,13 +2084,6 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                                        case RESERV:
                                                switch (val)
                                                {
-                                                       case DTK_CURRENT:
-                                                               ereport(ERROR,
-                                                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                                                errmsg("date/time value \"current\" is no longer supported")));
-                                                               return DTERR_BAD_FORMAT;
-                                                               break;
-
                                                        case DTK_NOW:
                                                                tmask = DTK_TIME_M;
                                                                *dtype = DTK_TIME;
@@ -2314,6 +2280,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                        GetCurrentDateTime(tmp);
                else
                {
+                       /* a date has to be specified */
+                       if ((fmask & DTK_DATE_M) != DTK_DATE_M)
+                               return DTERR_BAD_FORMAT;
                        tmp->tm_year = tm->tm_year;
                        tmp->tm_mon = tm->tm_mon;
                        tmp->tm_mday = tm->tm_mday;
@@ -2341,6 +2310,9 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                        GetCurrentDateTime(tmp);
                else
                {
+                       /* a date has to be specified */
+                       if ((fmask & DTK_DATE_M) != DTK_DATE_M)
+                               return DTERR_BAD_FORMAT;
                        tmp->tm_year = tm->tm_year;
                        tmp->tm_mon = tm->tm_mon;
                        tmp->tm_mday = tm->tm_mday;
@@ -3063,7 +3035,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
 }
 
 
-/* ClearPgTM
+/* ClearPgTm
  *
  * Zero out a pg_tm and associated fsec_t
  */
@@ -3162,7 +3134,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
                                 * handle signed float numbers and signed year-month values.
                                 */
 
-                               /* FALL THROUGH */
+                               /* FALLTHROUGH */
 
                        case DTK_DATE:
                        case DTK_NUMBER:
@@ -3593,6 +3565,7 @@ DecodeISO8601Interval(char *str,
                                                continue;
                                        }
                                        /* Else fall through to extended alternative format */
+                                       /* FALLTHROUGH */
                                case '-':               /* ISO 8601 4.4.3.3 Alternative Format,
                                                                 * Extended */
                                        if (havefield)
@@ -3671,6 +3644,7 @@ DecodeISO8601Interval(char *str,
                                                return 0;
                                        }
                                        /* Else fall through to extended alternative format */
+                                       /* FALLTHROUGH */
                                case ':':               /* ISO 8601 4.4.3.3 Alternative Format,
                                                                 * Extended */
                                        if (havefield)
@@ -4474,16 +4448,23 @@ CheckDateTokenTables(void)
 }
 
 /*
- * Common code for temporal protransform functions.  Types time, timetz,
- * timestamp and timestamptz each have a range of allowed precisions.  An
- * unspecified precision is rigorously equivalent to the highest specifiable
- * precision.
+ * Common code for temporal prosupport functions: simplify, if possible,
+ * a call to a temporal type's length-coercion function.
+ *
+ * Types time, timetz, timestamp and timestamptz each have a range of allowed
+ * precisions.  An unspecified precision is rigorously equivalent to the
+ * highest specifiable precision.  We can replace the function call with a
+ * no-op RelabelType if it is coercing to the same or higher precision as the
+ * input is known to have.
+ *
+ * The input Node is always a FuncExpr, but to reduce the #include footprint
+ * of datetime.h, we declare it as Node *.
  *
  * Note: timestamp_scale throws an error when the typmod is out of range, but
  * we can't get there from a cast: our typmodin will have caught it already.
  */
 Node *
-TemporalTransform(int32 max_precis, Node *node)
+TemporalSimplify(int32 max_precis, Node *node)
 {
        FuncExpr   *expr = castNode(FuncExpr, node);
        Node       *ret = NULL;
@@ -4686,7 +4667,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
                 * build tupdesc for result tuples. This must match this function's
                 * pg_proc entry!
                 */
-               tupdesc = CreateTemplateTupleDesc(3, false);
+               tupdesc = CreateTemplateTupleDesc(3);
                TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev",
                                                   TEXTOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
@@ -4813,7 +4794,7 @@ pg_timezone_names(PG_FUNCTION_ARGS)
                 * build tupdesc for result tuples. This must match this function's
                 * pg_proc entry!
                 */
-               tupdesc = CreateTemplateTupleDesc(4, false);
+               tupdesc = CreateTemplateTupleDesc(4);
                TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
                                                   TEXTOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev",
@@ -4851,16 +4832,15 @@ pg_timezone_names(PG_FUNCTION_ARGS)
                        continue;                       /* ignore if conversion fails */
 
                /*
-                * Ignore zic's rather silly "Factory" time zone.  The long string
-                * about "see zic manual page" is used in tzdata versions before
-                * 2016g; we can drop it someday when we're pretty sure no such data
-                * exists in the wild on platforms using --with-system-tzdata.  In
-                * 2016g and later, the time zone abbreviation "-00" is used for
-                * "Factory" as well as some invalid cases, all of which we can
-                * reasonably omit from the pg_timezone_names view.
+                * IANA's rather silly "Factory" time zone used to emit ridiculously
+                * long "abbreviations" such as "Local time zone must be set--see zic
+                * manual page" or "Local time zone must be set--use tzsetup".  While
+                * modern versions of tzdb emit the much saner "-00", it seems some
+                * benighted packagers are hacking the IANA data so that it continues
+                * to produce these strings.  To prevent producing a weirdly wide
+                * abbrev column, reject ridiculously long abbreviations.
                 */
-               if (tzn && (strcmp(tzn, "-00") == 0 ||
-                                       strcmp(tzn, "Local time zone must be set--see zic manual page") == 0))
+               if (tzn && strlen(tzn) > 31)
                        continue;
 
                /* Found a displayable zone */