PostgreSQL Source Code  git master
timestamp.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * timestamp.c
4  * Functions for the built-in SQL types "timestamp" and "interval".
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/adt/timestamp.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include <ctype.h>
19 #include <math.h>
20 #include <limits.h>
21 #include <sys/time.h>
22 
23 #include "access/xact.h"
24 #include "catalog/pg_type.h"
25 #include "common/int128.h"
26 #include "funcapi.h"
27 #include "libpq/pqformat.h"
28 #include "miscadmin.h"
29 #include "nodes/makefuncs.h"
30 #include "nodes/nodeFuncs.h"
31 #include "nodes/supportnodes.h"
32 #include "parser/scansup.h"
33 #include "utils/array.h"
34 #include "utils/builtins.h"
35 #include "utils/datetime.h"
36 #include "utils/float.h"
37 
38 /*
39  * gcc's -ffast-math switch breaks routines that expect exact results from
40  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
41  */
42 #ifdef __FAST_MATH__
43 #error -ffast-math is known to break this code
44 #endif
45 
46 #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
47 
48 /* Set at postmaster start */
50 
51 /* Set at configuration reload */
53 
54 typedef struct
55 {
59  int step_sign;
61 
62 typedef struct
63 {
67  int step_sign;
69 
70 
71 static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
72 static Timestamp dt2local(Timestamp dt, int timezone);
73 static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
74 static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
77 
78 
79 /* common code for timestamptypmodin and timestamptztypmodin */
80 static int32
82 {
83  int32 *tl;
84  int n;
85 
86  tl = ArrayGetIntegerTypmods(ta, &n);
87 
88  /*
89  * we're not too tense about good error message here because grammar
90  * shouldn't allow wrong number of modifiers for TIMESTAMP
91  */
92  if (n != 1)
93  ereport(ERROR,
94  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
95  errmsg("invalid type modifier")));
96 
97  return anytimestamp_typmod_check(istz, tl[0]);
98 }
99 
100 /* exported so parse_expr.c can use it */
101 int32
103 {
104  if (typmod < 0)
105  ereport(ERROR,
106  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
107  errmsg("TIMESTAMP(%d)%s precision must not be negative",
108  typmod, (istz ? " WITH TIME ZONE" : ""))));
109  if (typmod > MAX_TIMESTAMP_PRECISION)
110  {
112  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
113  errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
114  typmod, (istz ? " WITH TIME ZONE" : ""),
116  typmod = MAX_TIMESTAMP_PRECISION;
117  }
118 
119  return typmod;
120 }
121 
122 /* common code for timestamptypmodout and timestamptztypmodout */
123 static char *
124 anytimestamp_typmodout(bool istz, int32 typmod)
125 {
126  const char *tz = istz ? " with time zone" : " without time zone";
127 
128  if (typmod >= 0)
129  return psprintf("(%d)%s", (int) typmod, tz);
130  else
131  return psprintf("%s", tz);
132 }
133 
134 
135 /*****************************************************************************
136  * USER I/O ROUTINES *
137  *****************************************************************************/
138 
139 /* timestamp_in()
140  * Convert a string to internal form.
141  */
142 Datum
144 {
145  char *str = PG_GETARG_CSTRING(0);
146 
147 #ifdef NOT_USED
148  Oid typelem = PG_GETARG_OID(1);
149 #endif
150  int32 typmod = PG_GETARG_INT32(2);
151  Timestamp result;
152  fsec_t fsec;
153  struct pg_tm tt,
154  *tm = &tt;
155  int tz;
156  int dtype;
157  int nf;
158  int dterr;
159  char *field[MAXDATEFIELDS];
160  int ftype[MAXDATEFIELDS];
161  char workbuf[MAXDATELEN + MAXDATEFIELDS];
162 
163  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
164  field, ftype, MAXDATEFIELDS, &nf);
165  if (dterr == 0)
166  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
167  if (dterr != 0)
168  DateTimeParseError(dterr, str, "timestamp");
169 
170  switch (dtype)
171  {
172  case DTK_DATE:
173  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
174  ereport(ERROR,
175  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
176  errmsg("timestamp out of range: \"%s\"", str)));
177  break;
178 
179  case DTK_EPOCH:
180  result = SetEpochTimestamp();
181  break;
182 
183  case DTK_LATE:
184  TIMESTAMP_NOEND(result);
185  break;
186 
187  case DTK_EARLY:
188  TIMESTAMP_NOBEGIN(result);
189  break;
190 
191  default:
192  elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
193  dtype, str);
194  TIMESTAMP_NOEND(result);
195  }
196 
197  AdjustTimestampForTypmod(&result, typmod);
198 
199  PG_RETURN_TIMESTAMP(result);
200 }
201 
202 /* timestamp_out()
203  * Convert a timestamp to external form.
204  */
205 Datum
207 {
209  char *result;
210  struct pg_tm tt,
211  *tm = &tt;
212  fsec_t fsec;
213  char buf[MAXDATELEN + 1];
214 
215  if (TIMESTAMP_NOT_FINITE(timestamp))
216  EncodeSpecialTimestamp(timestamp, buf);
217  else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
218  EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
219  else
220  ereport(ERROR,
221  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
222  errmsg("timestamp out of range")));
223 
224  result = pstrdup(buf);
225  PG_RETURN_CSTRING(result);
226 }
227 
228 /*
229  * timestamp_recv - converts external binary format to timestamp
230  */
231 Datum
233 {
235 
236 #ifdef NOT_USED
237  Oid typelem = PG_GETARG_OID(1);
238 #endif
239  int32 typmod = PG_GETARG_INT32(2);
241  struct pg_tm tt,
242  *tm = &tt;
243  fsec_t fsec;
244 
245  timestamp = (Timestamp) pq_getmsgint64(buf);
246 
247  /* range check: see if timestamp_out would like it */
248  if (TIMESTAMP_NOT_FINITE(timestamp))
249  /* ok */ ;
250  else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
251  !IS_VALID_TIMESTAMP(timestamp))
252  ereport(ERROR,
253  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
254  errmsg("timestamp out of range")));
255 
256  AdjustTimestampForTypmod(&timestamp, typmod);
257 
258  PG_RETURN_TIMESTAMP(timestamp);
259 }
260 
261 /*
262  * timestamp_send - converts timestamp to binary format
263  */
264 Datum
266 {
269 
270  pq_begintypsend(&buf);
271  pq_sendint64(&buf, timestamp);
273 }
274 
275 Datum
277 {
279 
281 }
282 
283 Datum
285 {
286  int32 typmod = PG_GETARG_INT32(0);
287 
289 }
290 
291 
292 /*
293  * timestamp_support()
294  *
295  * Planner support function for the timestamp_scale() and timestamptz_scale()
296  * length coercion functions (we need not distinguish them here).
297  */
298 Datum
300 {
301  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
302  Node *ret = NULL;
303 
304  if (IsA(rawreq, SupportRequestSimplify))
305  {
307 
309  }
310 
311  PG_RETURN_POINTER(ret);
312 }
313 
314 /* timestamp_scale()
315  * Adjust time type for specified scale factor.
316  * Used by PostgreSQL type system to stuff columns.
317  */
318 Datum
320 {
322  int32 typmod = PG_GETARG_INT32(1);
323  Timestamp result;
324 
325  result = timestamp;
326 
327  AdjustTimestampForTypmod(&result, typmod);
328 
329  PG_RETURN_TIMESTAMP(result);
330 }
331 
332 /*
333  * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
334  * Works for either timestamp or timestamptz.
335  */
336 static void
338 {
339  static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
340  INT64CONST(1000000),
341  INT64CONST(100000),
342  INT64CONST(10000),
343  INT64CONST(1000),
344  INT64CONST(100),
345  INT64CONST(10),
346  INT64CONST(1)
347  };
348 
349  static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
350  INT64CONST(500000),
351  INT64CONST(50000),
352  INT64CONST(5000),
353  INT64CONST(500),
354  INT64CONST(50),
355  INT64CONST(5),
356  INT64CONST(0)
357  };
358 
359  if (!TIMESTAMP_NOT_FINITE(*time)
360  && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
361  {
362  if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
363  ereport(ERROR,
364  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
365  errmsg("timestamp(%d) precision must be between %d and %d",
366  typmod, 0, MAX_TIMESTAMP_PRECISION)));
367 
368  if (*time >= INT64CONST(0))
369  {
370  *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
371  TimestampScales[typmod];
372  }
373  else
374  {
375  *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
376  * TimestampScales[typmod]);
377  }
378  }
379 }
380 
381 
382 /* timestamptz_in()
383  * Convert a string to internal form.
384  */
385 Datum
387 {
388  char *str = PG_GETARG_CSTRING(0);
389 
390 #ifdef NOT_USED
391  Oid typelem = PG_GETARG_OID(1);
392 #endif
393  int32 typmod = PG_GETARG_INT32(2);
394  TimestampTz result;
395  fsec_t fsec;
396  struct pg_tm tt,
397  *tm = &tt;
398  int tz;
399  int dtype;
400  int nf;
401  int dterr;
402  char *field[MAXDATEFIELDS];
403  int ftype[MAXDATEFIELDS];
404  char workbuf[MAXDATELEN + MAXDATEFIELDS];
405 
406  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
407  field, ftype, MAXDATEFIELDS, &nf);
408  if (dterr == 0)
409  dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
410  if (dterr != 0)
411  DateTimeParseError(dterr, str, "timestamp with time zone");
412 
413  switch (dtype)
414  {
415  case DTK_DATE:
416  if (tm2timestamp(tm, fsec, &tz, &result) != 0)
417  ereport(ERROR,
418  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
419  errmsg("timestamp out of range: \"%s\"", str)));
420  break;
421 
422  case DTK_EPOCH:
423  result = SetEpochTimestamp();
424  break;
425 
426  case DTK_LATE:
427  TIMESTAMP_NOEND(result);
428  break;
429 
430  case DTK_EARLY:
431  TIMESTAMP_NOBEGIN(result);
432  break;
433 
434  default:
435  elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
436  dtype, str);
437  TIMESTAMP_NOEND(result);
438  }
439 
440  AdjustTimestampForTypmod(&result, typmod);
441 
442  PG_RETURN_TIMESTAMPTZ(result);
443 }
444 
445 /*
446  * Try to parse a timezone specification, and return its timezone offset value
447  * if it's acceptable. Otherwise, an error is thrown.
448  *
449  * Note: some code paths update tm->tm_isdst, and some don't; current callers
450  * don't care, so we don't bother being consistent.
451  */
452 static int
454 {
455  char tzname[TZ_STRLEN_MAX + 1];
456  int rt;
457  int tz;
458 
459  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
460 
461  /*
462  * Look up the requested timezone. First we try to interpret it as a
463  * numeric timezone specification; if DecodeTimezone decides it doesn't
464  * like the format, we look in the timezone abbreviation table (to handle
465  * cases like "EST"), and if that also fails, we look in the timezone
466  * database (to handle cases like "America/New_York"). (This matches the
467  * order in which timestamp input checks the cases; it's important because
468  * the timezone database unwisely uses a few zone names that are identical
469  * to offset abbreviations.)
470  *
471  * Note pg_tzset happily parses numeric input that DecodeTimezone would
472  * reject. To avoid having it accept input that would otherwise be seen
473  * as invalid, it's enough to disallow having a digit in the first
474  * position of our input string.
475  */
476  if (isdigit((unsigned char) *tzname))
477  ereport(ERROR,
478  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
479  errmsg("invalid input syntax for type %s: \"%s\"",
480  "numeric time zone", tzname),
481  errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
482 
483  rt = DecodeTimezone(tzname, &tz);
484  if (rt != 0)
485  {
486  char *lowzone;
487  int type,
488  val;
489  pg_tz *tzp;
490 
491  if (rt == DTERR_TZDISP_OVERFLOW)
492  ereport(ERROR,
493  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
494  errmsg("numeric time zone \"%s\" out of range", tzname)));
495  else if (rt != DTERR_BAD_FORMAT)
496  ereport(ERROR,
497  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
498  errmsg("time zone \"%s\" not recognized", tzname)));
499 
500  /* DecodeTimezoneAbbrev requires lowercase input */
501  lowzone = downcase_truncate_identifier(tzname,
502  strlen(tzname),
503  false);
504  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
505 
506  if (type == TZ || type == DTZ)
507  {
508  /* fixed-offset abbreviation */
509  tz = -val;
510  }
511  else if (type == DYNTZ)
512  {
513  /* dynamic-offset abbreviation, resolve using specified time */
514  tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
515  }
516  else
517  {
518  /* try it as a full zone name */
519  tzp = pg_tzset(tzname);
520  if (tzp)
521  tz = DetermineTimeZoneOffset(tm, tzp);
522  else
523  ereport(ERROR,
524  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
525  errmsg("time zone \"%s\" not recognized", tzname)));
526  }
527  }
528 
529  return tz;
530 }
531 
532 /*
533  * make_timestamp_internal
534  * workhorse for make_timestamp and make_timestamptz
535  */
536 static Timestamp
537 make_timestamp_internal(int year, int month, int day,
538  int hour, int min, double sec)
539 {
540  struct pg_tm tm;
542  TimeOffset time;
543  int dterr;
544  Timestamp result;
545 
546  tm.tm_year = year;
547  tm.tm_mon = month;
548  tm.tm_mday = day;
549 
550  /*
551  * Note: we'll reject zero or negative year values. Perhaps negatives
552  * should be allowed to represent BC years?
553  */
554  dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
555 
556  if (dterr != 0)
557  ereport(ERROR,
558  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
559  errmsg("date field value out of range: %d-%02d-%02d",
560  year, month, day)));
561 
562  if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
563  ereport(ERROR,
564  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
565  errmsg("date out of range: %d-%02d-%02d",
566  year, month, day)));
567 
568  date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
569 
570  /*
571  * This should match the checks in DecodeTimeOnly, except that since we're
572  * dealing with a float "sec" value, we also explicitly reject NaN. (An
573  * infinity input should get rejected by the range comparisons, but we
574  * can't be sure how those will treat a NaN.)
575  */
576  if (hour < 0 || min < 0 || min > MINS_PER_HOUR - 1 ||
577  isnan(sec) ||
578  sec < 0 || sec > SECS_PER_MINUTE ||
579  hour > HOURS_PER_DAY ||
580  /* test for > 24:00:00 */
581  (hour == HOURS_PER_DAY && (min > 0 || sec > 0)))
582  ereport(ERROR,
583  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
584  errmsg("time field value out of range: %d:%02d:%02g",
585  hour, min, sec)));
586 
587  /* This should match tm2time */
588  time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
589  * USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
590 
591  result = date * USECS_PER_DAY + time;
592  /* check for major overflow */
593  if ((result - time) / USECS_PER_DAY != date)
594  ereport(ERROR,
595  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
596  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
597  year, month, day,
598  hour, min, sec)));
599 
600  /* check for just-barely overflow (okay except time-of-day wraps) */
601  /* caution: we want to allow 1999-12-31 24:00:00 */
602  if ((result < 0 && date > 0) ||
603  (result > 0 && date < -1))
604  ereport(ERROR,
605  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
606  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
607  year, month, day,
608  hour, min, sec)));
609 
610  /* final range check catches just-out-of-range timestamps */
611  if (!IS_VALID_TIMESTAMP(result))
612  ereport(ERROR,
613  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
614  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
615  year, month, day,
616  hour, min, sec)));
617 
618  return result;
619 }
620 
621 /*
622  * make_timestamp() - timestamp constructor
623  */
624 Datum
626 {
627  int32 year = PG_GETARG_INT32(0);
628  int32 month = PG_GETARG_INT32(1);
629  int32 mday = PG_GETARG_INT32(2);
630  int32 hour = PG_GETARG_INT32(3);
631  int32 min = PG_GETARG_INT32(4);
632  float8 sec = PG_GETARG_FLOAT8(5);
633  Timestamp result;
634 
635  result = make_timestamp_internal(year, month, mday,
636  hour, min, sec);
637 
638  PG_RETURN_TIMESTAMP(result);
639 }
640 
641 /*
642  * make_timestamptz() - timestamp with time zone constructor
643  */
644 Datum
646 {
647  int32 year = PG_GETARG_INT32(0);
648  int32 month = PG_GETARG_INT32(1);
649  int32 mday = PG_GETARG_INT32(2);
650  int32 hour = PG_GETARG_INT32(3);
651  int32 min = PG_GETARG_INT32(4);
652  float8 sec = PG_GETARG_FLOAT8(5);
653  Timestamp result;
654 
655  result = make_timestamp_internal(year, month, mday,
656  hour, min, sec);
657 
659 }
660 
661 /*
662  * Construct a timestamp with time zone.
663  * As above, but the time zone is specified as seventh argument.
664  */
665 Datum
667 {
668  int32 year = PG_GETARG_INT32(0);
669  int32 month = PG_GETARG_INT32(1);
670  int32 mday = PG_GETARG_INT32(2);
671  int32 hour = PG_GETARG_INT32(3);
672  int32 min = PG_GETARG_INT32(4);
673  float8 sec = PG_GETARG_FLOAT8(5);
675  TimestampTz result;
677  struct pg_tm tt;
678  int tz;
679  fsec_t fsec;
680 
681  timestamp = make_timestamp_internal(year, month, mday,
682  hour, min, sec);
683 
684  if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
685  ereport(ERROR,
686  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
687  errmsg("timestamp out of range")));
688 
689  tz = parse_sane_timezone(&tt, zone);
690 
691  result = dt2local(timestamp, -tz);
692 
693  if (!IS_VALID_TIMESTAMP(result))
694  ereport(ERROR,
695  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
696  errmsg("timestamp out of range")));
697 
698  PG_RETURN_TIMESTAMPTZ(result);
699 }
700 
701 /*
702  * to_timestamp(double precision)
703  * Convert UNIX epoch to timestamptz.
704  */
705 Datum
707 {
708  float8 seconds = PG_GETARG_FLOAT8(0);
709  TimestampTz result;
710 
711  /* Deal with NaN and infinite inputs ... */
712  if (isnan(seconds))
713  ereport(ERROR,
714  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
715  errmsg("timestamp cannot be NaN")));
716 
717  if (isinf(seconds))
718  {
719  if (seconds < 0)
720  TIMESTAMP_NOBEGIN(result);
721  else
722  TIMESTAMP_NOEND(result);
723  }
724  else
725  {
726  /* Out of range? */
727  if (seconds <
729  || seconds >=
731  ereport(ERROR,
732  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
733  errmsg("timestamp out of range: \"%g\"", seconds)));
734 
735  /* Convert UNIX epoch to Postgres epoch */
737 
738  seconds = rint(seconds * USECS_PER_SEC);
739  result = (int64) seconds;
740 
741  /* Recheck in case roundoff produces something just out of range */
742  if (!IS_VALID_TIMESTAMP(result))
743  ereport(ERROR,
744  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
745  errmsg("timestamp out of range: \"%g\"",
746  PG_GETARG_FLOAT8(0))));
747  }
748 
749  PG_RETURN_TIMESTAMP(result);
750 }
751 
752 /* timestamptz_out()
753  * Convert a timestamp to external form.
754  */
755 Datum
757 {
759  char *result;
760  int tz;
761  struct pg_tm tt,
762  *tm = &tt;
763  fsec_t fsec;
764  const char *tzn;
765  char buf[MAXDATELEN + 1];
766 
767  if (TIMESTAMP_NOT_FINITE(dt))
768  EncodeSpecialTimestamp(dt, buf);
769  else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
770  EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
771  else
772  ereport(ERROR,
773  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
774  errmsg("timestamp out of range")));
775 
776  result = pstrdup(buf);
777  PG_RETURN_CSTRING(result);
778 }
779 
780 /*
781  * timestamptz_recv - converts external binary format to timestamptz
782  */
783 Datum
785 {
787 
788 #ifdef NOT_USED
789  Oid typelem = PG_GETARG_OID(1);
790 #endif
791  int32 typmod = PG_GETARG_INT32(2);
793  int tz;
794  struct pg_tm tt,
795  *tm = &tt;
796  fsec_t fsec;
797 
798  timestamp = (TimestampTz) pq_getmsgint64(buf);
799 
800  /* range check: see if timestamptz_out would like it */
801  if (TIMESTAMP_NOT_FINITE(timestamp))
802  /* ok */ ;
803  else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
804  !IS_VALID_TIMESTAMP(timestamp))
805  ereport(ERROR,
806  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
807  errmsg("timestamp out of range")));
808 
809  AdjustTimestampForTypmod(&timestamp, typmod);
810 
811  PG_RETURN_TIMESTAMPTZ(timestamp);
812 }
813 
814 /*
815  * timestamptz_send - converts timestamptz to binary format
816  */
817 Datum
819 {
822 
823  pq_begintypsend(&buf);
824  pq_sendint64(&buf, timestamp);
826 }
827 
828 Datum
830 {
832 
834 }
835 
836 Datum
838 {
839  int32 typmod = PG_GETARG_INT32(0);
840 
842 }
843 
844 
845 /* timestamptz_scale()
846  * Adjust time type for specified scale factor.
847  * Used by PostgreSQL type system to stuff columns.
848  */
849 Datum
851 {
853  int32 typmod = PG_GETARG_INT32(1);
854  TimestampTz result;
855 
856  result = timestamp;
857 
858  AdjustTimestampForTypmod(&result, typmod);
859 
860  PG_RETURN_TIMESTAMPTZ(result);
861 }
862 
863 
864 /* interval_in()
865  * Convert a string to internal form.
866  *
867  * External format(s):
868  * Uses the generic date/time parsing and decoding routines.
869  */
870 Datum
872 {
873  char *str = PG_GETARG_CSTRING(0);
874 
875 #ifdef NOT_USED
876  Oid typelem = PG_GETARG_OID(1);
877 #endif
878  int32 typmod = PG_GETARG_INT32(2);
879  Interval *result;
880  fsec_t fsec;
881  struct pg_tm tt,
882  *tm = &tt;
883  int dtype;
884  int nf;
885  int range;
886  int dterr;
887  char *field[MAXDATEFIELDS];
888  int ftype[MAXDATEFIELDS];
889  char workbuf[256];
890 
891  tm->tm_year = 0;
892  tm->tm_mon = 0;
893  tm->tm_mday = 0;
894  tm->tm_hour = 0;
895  tm->tm_min = 0;
896  tm->tm_sec = 0;
897  fsec = 0;
898 
899  if (typmod >= 0)
900  range = INTERVAL_RANGE(typmod);
901  else
902  range = INTERVAL_FULL_RANGE;
903 
904  dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
905  ftype, MAXDATEFIELDS, &nf);
906  if (dterr == 0)
907  dterr = DecodeInterval(field, ftype, nf, range,
908  &dtype, tm, &fsec);
909 
910  /* if those functions think it's a bad format, try ISO8601 style */
911  if (dterr == DTERR_BAD_FORMAT)
912  dterr = DecodeISO8601Interval(str,
913  &dtype, tm, &fsec);
914 
915  if (dterr != 0)
916  {
917  if (dterr == DTERR_FIELD_OVERFLOW)
918  dterr = DTERR_INTERVAL_OVERFLOW;
919  DateTimeParseError(dterr, str, "interval");
920  }
921 
922  result = (Interval *) palloc(sizeof(Interval));
923 
924  switch (dtype)
925  {
926  case DTK_DELTA:
927  if (tm2interval(tm, fsec, result) != 0)
928  ereport(ERROR,
929  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
930  errmsg("interval out of range")));
931  break;
932 
933  default:
934  elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
935  dtype, str);
936  }
937 
938  AdjustIntervalForTypmod(result, typmod);
939 
940  PG_RETURN_INTERVAL_P(result);
941 }
942 
943 /* interval_out()
944  * Convert a time span to external form.
945  */
946 Datum
948 {
949  Interval *span = PG_GETARG_INTERVAL_P(0);
950  char *result;
951  struct pg_tm tt,
952  *tm = &tt;
953  fsec_t fsec;
954  char buf[MAXDATELEN + 1];
955 
956  if (interval2tm(*span, tm, &fsec) != 0)
957  elog(ERROR, "could not convert interval to tm");
958 
959  EncodeInterval(tm, fsec, IntervalStyle, buf);
960 
961  result = pstrdup(buf);
962  PG_RETURN_CSTRING(result);
963 }
964 
965 /*
966  * interval_recv - converts external binary format to interval
967  */
968 Datum
970 {
972 
973 #ifdef NOT_USED
974  Oid typelem = PG_GETARG_OID(1);
975 #endif
976  int32 typmod = PG_GETARG_INT32(2);
978 
979  interval = (Interval *) palloc(sizeof(Interval));
980 
981  interval->time = pq_getmsgint64(buf);
982  interval->day = pq_getmsgint(buf, sizeof(interval->day));
983  interval->month = pq_getmsgint(buf, sizeof(interval->month));
984 
985  AdjustIntervalForTypmod(interval, typmod);
986 
987  PG_RETURN_INTERVAL_P(interval);
988 }
989 
990 /*
991  * interval_send - converts interval to binary format
992  */
993 Datum
995 {
998 
999  pq_begintypsend(&buf);
1000  pq_sendint64(&buf, interval->time);
1001  pq_sendint32(&buf, interval->day);
1002  pq_sendint32(&buf, interval->month);
1004 }
1005 
1006 /*
1007  * The interval typmod stores a "range" in its high 16 bits and a "precision"
1008  * in its low 16 bits. Both contribute to defining the resolution of the
1009  * type. Range addresses resolution granules larger than one second, and
1010  * precision specifies resolution below one second. This representation can
1011  * express all SQL standard resolutions, but we implement them all in terms of
1012  * truncating rightward from some position. Range is a bitmap of permitted
1013  * fields, but only the temporally-smallest such field is significant to our
1014  * calculations. Precision is a count of sub-second decimal places to retain.
1015  * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation
1016  * semantics as choosing MAX_INTERVAL_PRECISION.
1017  */
1018 Datum
1020 {
1022  int32 *tl;
1023  int n;
1024  int32 typmod;
1025 
1026  tl = ArrayGetIntegerTypmods(ta, &n);
1027 
1028  /*
1029  * tl[0] - interval range (fields bitmask) tl[1] - precision (optional)
1030  *
1031  * Note we must validate tl[0] even though it's normally guaranteed
1032  * correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
1033  */
1034  if (n > 0)
1035  {
1036  switch (tl[0])
1037  {
1038  case INTERVAL_MASK(YEAR):
1039  case INTERVAL_MASK(MONTH):
1040  case INTERVAL_MASK(DAY):
1041  case INTERVAL_MASK(HOUR):
1042  case INTERVAL_MASK(MINUTE):
1043  case INTERVAL_MASK(SECOND):
1051  case INTERVAL_FULL_RANGE:
1052  /* all OK */
1053  break;
1054  default:
1055  ereport(ERROR,
1056  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1057  errmsg("invalid INTERVAL type modifier")));
1058  }
1059  }
1060 
1061  if (n == 1)
1062  {
1063  if (tl[0] != INTERVAL_FULL_RANGE)
1064  typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
1065  else
1066  typmod = -1;
1067  }
1068  else if (n == 2)
1069  {
1070  if (tl[1] < 0)
1071  ereport(ERROR,
1072  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1073  errmsg("INTERVAL(%d) precision must not be negative",
1074  tl[1])));
1075  if (tl[1] > MAX_INTERVAL_PRECISION)
1076  {
1077  ereport(WARNING,
1078  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1079  errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
1080  tl[1], MAX_INTERVAL_PRECISION)));
1081  typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
1082  }
1083  else
1084  typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
1085  }
1086  else
1087  {
1088  ereport(ERROR,
1089  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1090  errmsg("invalid INTERVAL type modifier")));
1091  typmod = 0; /* keep compiler quiet */
1092  }
1093 
1094  PG_RETURN_INT32(typmod);
1095 }
1096 
1097 Datum
1099 {
1100  int32 typmod = PG_GETARG_INT32(0);
1101  char *res = (char *) palloc(64);
1102  int fields;
1103  int precision;
1104  const char *fieldstr;
1105 
1106  if (typmod < 0)
1107  {
1108  *res = '\0';
1109  PG_RETURN_CSTRING(res);
1110  }
1111 
1112  fields = INTERVAL_RANGE(typmod);
1113  precision = INTERVAL_PRECISION(typmod);
1114 
1115  switch (fields)
1116  {
1117  case INTERVAL_MASK(YEAR):
1118  fieldstr = " year";
1119  break;
1120  case INTERVAL_MASK(MONTH):
1121  fieldstr = " month";
1122  break;
1123  case INTERVAL_MASK(DAY):
1124  fieldstr = " day";
1125  break;
1126  case INTERVAL_MASK(HOUR):
1127  fieldstr = " hour";
1128  break;
1129  case INTERVAL_MASK(MINUTE):
1130  fieldstr = " minute";
1131  break;
1132  case INTERVAL_MASK(SECOND):
1133  fieldstr = " second";
1134  break;
1136  fieldstr = " year to month";
1137  break;
1139  fieldstr = " day to hour";
1140  break;
1142  fieldstr = " day to minute";
1143  break;
1145  fieldstr = " day to second";
1146  break;
1148  fieldstr = " hour to minute";
1149  break;
1151  fieldstr = " hour to second";
1152  break;
1154  fieldstr = " minute to second";
1155  break;
1156  case INTERVAL_FULL_RANGE:
1157  fieldstr = "";
1158  break;
1159  default:
1160  elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
1161  fieldstr = "";
1162  break;
1163  }
1164 
1165  if (precision != INTERVAL_FULL_PRECISION)
1166  snprintf(res, 64, "%s(%d)", fieldstr, precision);
1167  else
1168  snprintf(res, 64, "%s", fieldstr);
1169 
1170  PG_RETURN_CSTRING(res);
1171 }
1172 
1173 /*
1174  * Given an interval typmod value, return a code for the least-significant
1175  * field that the typmod allows to be nonzero, for instance given
1176  * INTERVAL DAY TO HOUR we want to identify "hour".
1177  *
1178  * The results should be ordered by field significance, which means
1179  * we can't use the dt.h macros YEAR etc, because for some odd reason
1180  * they aren't ordered that way. Instead, arbitrarily represent
1181  * SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5.
1182  */
1183 static int
1185 {
1186  if (typmod < 0)
1187  return 0; /* SECOND */
1188 
1189  switch (INTERVAL_RANGE(typmod))
1190  {
1191  case INTERVAL_MASK(YEAR):
1192  return 5; /* YEAR */
1193  case INTERVAL_MASK(MONTH):
1194  return 4; /* MONTH */
1195  case INTERVAL_MASK(DAY):
1196  return 3; /* DAY */
1197  case INTERVAL_MASK(HOUR):
1198  return 2; /* HOUR */
1199  case INTERVAL_MASK(MINUTE):
1200  return 1; /* MINUTE */
1201  case INTERVAL_MASK(SECOND):
1202  return 0; /* SECOND */
1204  return 4; /* MONTH */
1206  return 2; /* HOUR */
1208  return 1; /* MINUTE */
1210  return 0; /* SECOND */
1212  return 1; /* MINUTE */
1214  return 0; /* SECOND */
1216  return 0; /* SECOND */
1217  case INTERVAL_FULL_RANGE:
1218  return 0; /* SECOND */
1219  default:
1220  elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
1221  break;
1222  }
1223  return 0; /* can't get here, but keep compiler quiet */
1224 }
1225 
1226 
1227 /*
1228  * interval_support()
1229  *
1230  * Planner support function for interval_scale().
1231  *
1232  * Flatten superfluous calls to interval_scale(). The interval typmod is
1233  * complex to permit accepting and regurgitating all SQL standard variations.
1234  * For truncation purposes, it boils down to a single, simple granularity.
1235  */
1236 Datum
1238 {
1239  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1240  Node *ret = NULL;
1241 
1242  if (IsA(rawreq, SupportRequestSimplify))
1243  {
1245  FuncExpr *expr = req->fcall;
1246  Node *typmod;
1247 
1248  Assert(list_length(expr->args) >= 2);
1249 
1250  typmod = (Node *) lsecond(expr->args);
1251 
1252  if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
1253  {
1254  Node *source = (Node *) linitial(expr->args);
1255  int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
1256  bool noop;
1257 
1258  if (new_typmod < 0)
1259  noop = true;
1260  else
1261  {
1262  int32 old_typmod = exprTypmod(source);
1263  int old_least_field;
1264  int new_least_field;
1265  int old_precis;
1266  int new_precis;
1267 
1268  old_least_field = intervaltypmodleastfield(old_typmod);
1269  new_least_field = intervaltypmodleastfield(new_typmod);
1270  if (old_typmod < 0)
1271  old_precis = INTERVAL_FULL_PRECISION;
1272  else
1273  old_precis = INTERVAL_PRECISION(old_typmod);
1274  new_precis = INTERVAL_PRECISION(new_typmod);
1275 
1276  /*
1277  * Cast is a no-op if least field stays the same or decreases
1278  * while precision stays the same or increases. But
1279  * precision, which is to say, sub-second precision, only
1280  * affects ranges that include SECOND.
1281  */
1282  noop = (new_least_field <= old_least_field) &&
1283  (old_least_field > 0 /* SECOND */ ||
1284  new_precis >= MAX_INTERVAL_PRECISION ||
1285  new_precis >= old_precis);
1286  }
1287  if (noop)
1288  ret = relabel_to_typmod(source, new_typmod);
1289  }
1290  }
1291 
1292  PG_RETURN_POINTER(ret);
1293 }
1294 
1295 /* interval_scale()
1296  * Adjust interval type for specified fields.
1297  * Used by PostgreSQL type system to stuff columns.
1298  */
1299 Datum
1301 {
1303  int32 typmod = PG_GETARG_INT32(1);
1304  Interval *result;
1305 
1306  result = palloc(sizeof(Interval));
1307  *result = *interval;
1308 
1309  AdjustIntervalForTypmod(result, typmod);
1310 
1311  PG_RETURN_INTERVAL_P(result);
1312 }
1313 
1314 /*
1315  * Adjust interval for specified precision, in both YEAR to SECOND
1316  * range and sub-second precision.
1317  */
1318 static void
1320 {
1321  static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
1322  INT64CONST(1000000),
1323  INT64CONST(100000),
1324  INT64CONST(10000),
1325  INT64CONST(1000),
1326  INT64CONST(100),
1327  INT64CONST(10),
1328  INT64CONST(1)
1329  };
1330 
1331  static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
1332  INT64CONST(500000),
1333  INT64CONST(50000),
1334  INT64CONST(5000),
1335  INT64CONST(500),
1336  INT64CONST(50),
1337  INT64CONST(5),
1338  INT64CONST(0)
1339  };
1340 
1341  /*
1342  * Unspecified range and precision? Then not necessary to adjust. Setting
1343  * typmod to -1 is the convention for all data types.
1344  */
1345  if (typmod >= 0)
1346  {
1347  int range = INTERVAL_RANGE(typmod);
1348  int precision = INTERVAL_PRECISION(typmod);
1349 
1350  /*
1351  * Our interpretation of intervals with a limited set of fields is
1352  * that fields to the right of the last one specified are zeroed out,
1353  * but those to the left of it remain valid. Thus for example there
1354  * is no operational difference between INTERVAL YEAR TO MONTH and
1355  * INTERVAL MONTH. In some cases we could meaningfully enforce that
1356  * higher-order fields are zero; for example INTERVAL DAY could reject
1357  * nonzero "month" field. However that seems a bit pointless when we
1358  * can't do it consistently. (We cannot enforce a range limit on the
1359  * highest expected field, since we do not have any equivalent of
1360  * SQL's <interval leading field precision>.) If we ever decide to
1361  * revisit this, interval_support will likely require adjusting.
1362  *
1363  * Note: before PG 8.4 we interpreted a limited set of fields as
1364  * actually causing a "modulo" operation on a given value, potentially
1365  * losing high-order as well as low-order information. But there is
1366  * no support for such behavior in the standard, and it seems fairly
1367  * undesirable on data consistency grounds anyway. Now we only
1368  * perform truncation or rounding of low-order fields.
1369  */
1370  if (range == INTERVAL_FULL_RANGE)
1371  {
1372  /* Do nothing... */
1373  }
1374  else if (range == INTERVAL_MASK(YEAR))
1375  {
1376  interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
1377  interval->day = 0;
1378  interval->time = 0;
1379  }
1380  else if (range == INTERVAL_MASK(MONTH))
1381  {
1382  interval->day = 0;
1383  interval->time = 0;
1384  }
1385  /* YEAR TO MONTH */
1386  else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
1387  {
1388  interval->day = 0;
1389  interval->time = 0;
1390  }
1391  else if (range == INTERVAL_MASK(DAY))
1392  {
1393  interval->time = 0;
1394  }
1395  else if (range == INTERVAL_MASK(HOUR))
1396  {
1397  interval->time = (interval->time / USECS_PER_HOUR) *
1399  }
1400  else if (range == INTERVAL_MASK(MINUTE))
1401  {
1402  interval->time = (interval->time / USECS_PER_MINUTE) *
1404  }
1405  else if (range == INTERVAL_MASK(SECOND))
1406  {
1407  /* fractional-second rounding will be dealt with below */
1408  }
1409  /* DAY TO HOUR */
1410  else if (range == (INTERVAL_MASK(DAY) |
1411  INTERVAL_MASK(HOUR)))
1412  {
1413  interval->time = (interval->time / USECS_PER_HOUR) *
1415  }
1416  /* DAY TO MINUTE */
1417  else if (range == (INTERVAL_MASK(DAY) |
1418  INTERVAL_MASK(HOUR) |
1420  {
1421  interval->time = (interval->time / USECS_PER_MINUTE) *
1423  }
1424  /* DAY TO SECOND */
1425  else if (range == (INTERVAL_MASK(DAY) |
1426  INTERVAL_MASK(HOUR) |
1429  {
1430  /* fractional-second rounding will be dealt with below */
1431  }
1432  /* HOUR TO MINUTE */
1433  else if (range == (INTERVAL_MASK(HOUR) |
1435  {
1436  interval->time = (interval->time / USECS_PER_MINUTE) *
1438  }
1439  /* HOUR TO SECOND */
1440  else if (range == (INTERVAL_MASK(HOUR) |
1443  {
1444  /* fractional-second rounding will be dealt with below */
1445  }
1446  /* MINUTE TO SECOND */
1447  else if (range == (INTERVAL_MASK(MINUTE) |
1449  {
1450  /* fractional-second rounding will be dealt with below */
1451  }
1452  else
1453  elog(ERROR, "unrecognized interval typmod: %d", typmod);
1454 
1455  /* Need to adjust sub-second precision? */
1456  if (precision != INTERVAL_FULL_PRECISION)
1457  {
1458  if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
1459  ereport(ERROR,
1460  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1461  errmsg("interval(%d) precision must be between %d and %d",
1462  precision, 0, MAX_INTERVAL_PRECISION)));
1463 
1464  if (interval->time >= INT64CONST(0))
1465  {
1466  interval->time = ((interval->time +
1467  IntervalOffsets[precision]) /
1468  IntervalScales[precision]) *
1469  IntervalScales[precision];
1470  }
1471  else
1472  {
1473  interval->time = -(((-interval->time +
1474  IntervalOffsets[precision]) /
1475  IntervalScales[precision]) *
1476  IntervalScales[precision]);
1477  }
1478  }
1479  }
1480 }
1481 
1482 /*
1483  * make_interval - numeric Interval constructor
1484  */
1485 Datum
1487 {
1488  int32 years = PG_GETARG_INT32(0);
1490  int32 weeks = PG_GETARG_INT32(2);
1491  int32 days = PG_GETARG_INT32(3);
1492  int32 hours = PG_GETARG_INT32(4);
1493  int32 mins = PG_GETARG_INT32(5);
1494  double secs = PG_GETARG_FLOAT8(6);
1495  Interval *result;
1496 
1497  /*
1498  * Reject out-of-range inputs. We really ought to check the integer
1499  * inputs as well, but it's not entirely clear what limits to apply.
1500  */
1501  if (isinf(secs) || isnan(secs))
1502  ereport(ERROR,
1503  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1504  errmsg("interval out of range")));
1505 
1506  result = (Interval *) palloc(sizeof(Interval));
1507  result->month = years * MONTHS_PER_YEAR + months;
1508  result->day = weeks * 7 + days;
1509 
1510  secs = rint(secs * USECS_PER_SEC);
1511  result->time = hours * ((int64) SECS_PER_HOUR * USECS_PER_SEC) +
1512  mins * ((int64) SECS_PER_MINUTE * USECS_PER_SEC) +
1513  (int64) secs;
1514 
1515  PG_RETURN_INTERVAL_P(result);
1516 }
1517 
1518 /* EncodeSpecialTimestamp()
1519  * Convert reserved timestamp data type to string.
1520  */
1521 void
1523 {
1524  if (TIMESTAMP_IS_NOBEGIN(dt))
1525  strcpy(str, EARLY);
1526  else if (TIMESTAMP_IS_NOEND(dt))
1527  strcpy(str, LATE);
1528  else /* shouldn't happen */
1529  elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
1530 }
1531 
1532 Datum
1534 {
1536 }
1537 
1538 Datum
1540 {
1542 }
1543 
1544 Datum
1546 {
1548 }
1549 
1550 Datum
1552 {
1554 }
1555 
1556 Datum
1558 {
1560 }
1561 
1562 /*
1563  * GetCurrentTimestamp -- get the current operating system time
1564  *
1565  * Result is in the form of a TimestampTz value, and is expressed to the
1566  * full precision of the gettimeofday() syscall
1567  */
1570 {
1571  TimestampTz result;
1572  struct timeval tp;
1573 
1574  gettimeofday(&tp, NULL);
1575 
1576  result = (TimestampTz) tp.tv_sec -
1578  result = (result * USECS_PER_SEC) + tp.tv_usec;
1579 
1580  return result;
1581 }
1582 
1583 /*
1584  * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
1585  */
1588 {
1589  TimestampTz ts;
1590 
1592  if (typmod >= 0)
1593  AdjustTimestampForTypmod(&ts, typmod);
1594  return ts;
1595 }
1596 
1597 /*
1598  * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
1599  */
1600 Timestamp
1602 {
1603  Timestamp ts;
1604 
1606  if (typmod >= 0)
1607  AdjustTimestampForTypmod(&ts, typmod);
1608  return ts;
1609 }
1610 
1611 /*
1612  * timeofday(*) -- returns the current time as a text.
1613  */
1614 Datum
1616 {
1617  struct timeval tp;
1618  char templ[128];
1619  char buf[128];
1620  pg_time_t tt;
1621 
1622  gettimeofday(&tp, NULL);
1623  tt = (pg_time_t) tp.tv_sec;
1624  pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1626  snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1627 
1629 }
1630 
1631 /*
1632  * TimestampDifference -- convert the difference between two timestamps
1633  * into integer seconds and microseconds
1634  *
1635  * Both inputs must be ordinary finite timestamps (in current usage,
1636  * they'll be results from GetCurrentTimestamp()).
1637  *
1638  * We expect start_time <= stop_time. If not, we return zeros; for current
1639  * callers there is no need to be tense about which way division rounds on
1640  * negative inputs.
1641  */
1642 void
1644  long *secs, int *microsecs)
1645 {
1646  TimestampTz diff = stop_time - start_time;
1647 
1648  if (diff <= 0)
1649  {
1650  *secs = 0;
1651  *microsecs = 0;
1652  }
1653  else
1654  {
1655  *secs = (long) (diff / USECS_PER_SEC);
1656  *microsecs = (int) (diff % USECS_PER_SEC);
1657  }
1658 }
1659 
1660 /*
1661  * TimestampDifferenceExceeds -- report whether the difference between two
1662  * timestamps is >= a threshold (expressed in milliseconds)
1663  *
1664  * Both inputs must be ordinary finite timestamps (in current usage,
1665  * they'll be results from GetCurrentTimestamp()).
1666  */
1667 bool
1669  TimestampTz stop_time,
1670  int msec)
1671 {
1672  TimestampTz diff = stop_time - start_time;
1673 
1674  return (diff >= msec * INT64CONST(1000));
1675 }
1676 
1677 /*
1678  * Convert a time_t to TimestampTz.
1679  *
1680  * We do not use time_t internally in Postgres, but this is provided for use
1681  * by functions that need to interpret, say, a stat(2) result.
1682  *
1683  * To avoid having the function's ABI vary depending on the width of time_t,
1684  * we declare the argument as pg_time_t, which is cast-compatible with
1685  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1686  * This detail should be invisible to callers, at least at source code level.
1687  */
1690 {
1691  TimestampTz result;
1692 
1693  result = (TimestampTz) tm -
1695  result *= USECS_PER_SEC;
1696 
1697  return result;
1698 }
1699 
1700 /*
1701  * Convert a TimestampTz to time_t.
1702  *
1703  * This too is just marginally useful, but some places need it.
1704  *
1705  * To avoid having the function's ABI vary depending on the width of time_t,
1706  * we declare the result as pg_time_t, which is cast-compatible with
1707  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1708  * This detail should be invisible to callers, at least at source code level.
1709  */
1710 pg_time_t
1712 {
1713  pg_time_t result;
1714 
1715  result = (pg_time_t) (t / USECS_PER_SEC +
1717 
1718  return result;
1719 }
1720 
1721 /*
1722  * Produce a C-string representation of a TimestampTz.
1723  *
1724  * This is mostly for use in emitting messages. The primary difference
1725  * from timestamptz_out is that we force the output format to ISO. Note
1726  * also that the result is in a static buffer, not pstrdup'd.
1727  */
1728 const char *
1730 {
1731  static char buf[MAXDATELEN + 1];
1732  int tz;
1733  struct pg_tm tt,
1734  *tm = &tt;
1735  fsec_t fsec;
1736  const char *tzn;
1737 
1738  if (TIMESTAMP_NOT_FINITE(t))
1739  EncodeSpecialTimestamp(t, buf);
1740  else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
1741  EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1742  else
1743  strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1744 
1745  return buf;
1746 }
1747 
1748 
1749 void
1750 dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
1751 {
1752  TimeOffset time;
1753 
1754  time = jd;
1755 
1756  *hour = time / USECS_PER_HOUR;
1757  time -= (*hour) * USECS_PER_HOUR;
1758  *min = time / USECS_PER_MINUTE;
1759  time -= (*min) * USECS_PER_MINUTE;
1760  *sec = time / USECS_PER_SEC;
1761  *fsec = time - (*sec * USECS_PER_SEC);
1762 } /* dt2time() */
1763 
1764 
1765 /*
1766  * timestamp2tm() - Convert timestamp data type to POSIX time structure.
1767  *
1768  * Note that year is _not_ 1900-based, but is an explicit full value.
1769  * Also, month is one-based, _not_ zero-based.
1770  * Returns:
1771  * 0 on success
1772  * -1 on out of range
1773  *
1774  * If attimezone is NULL, the global timezone setting will be used.
1775  */
1776 int
1777 timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
1778 {
1779  Timestamp date;
1780  Timestamp time;
1781  pg_time_t utime;
1782 
1783  /* Use session timezone if caller asks for default */
1784  if (attimezone == NULL)
1785  attimezone = session_timezone;
1786 
1787  time = dt;
1788  TMODULO(time, date, USECS_PER_DAY);
1789 
1790  if (time < INT64CONST(0))
1791  {
1792  time += USECS_PER_DAY;
1793  date -= 1;
1794  }
1795 
1796  /* add offset to go from J2000 back to standard Julian date */
1797  date += POSTGRES_EPOCH_JDATE;
1798 
1799  /* Julian day routine does not work for negative Julian days */
1800  if (date < 0 || date > (Timestamp) INT_MAX)
1801  return -1;
1802 
1803  j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1804  dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
1805 
1806  /* Done if no TZ conversion wanted */
1807  if (tzp == NULL)
1808  {
1809  tm->tm_isdst = -1;
1810  tm->tm_gmtoff = 0;
1811  tm->tm_zone = NULL;
1812  if (tzn != NULL)
1813  *tzn = NULL;
1814  return 0;
1815  }
1816 
1817  /*
1818  * If the time falls within the range of pg_time_t, use pg_localtime() to
1819  * rotate to the local time zone.
1820  *
1821  * First, convert to an integral timestamp, avoiding possibly
1822  * platform-specific roundoff-in-wrong-direction errors, and adjust to
1823  * Unix epoch. Then see if we can convert to pg_time_t without loss. This
1824  * coding avoids hardwiring any assumptions about the width of pg_time_t,
1825  * so it should behave sanely on machines without int64.
1826  */
1827  dt = (dt - *fsec) / USECS_PER_SEC +
1829  utime = (pg_time_t) dt;
1830  if ((Timestamp) utime == dt)
1831  {
1832  struct pg_tm *tx = pg_localtime(&utime, attimezone);
1833 
1834  tm->tm_year = tx->tm_year + 1900;
1835  tm->tm_mon = tx->tm_mon + 1;
1836  tm->tm_mday = tx->tm_mday;
1837  tm->tm_hour = tx->tm_hour;
1838  tm->tm_min = tx->tm_min;
1839  tm->tm_sec = tx->tm_sec;
1840  tm->tm_isdst = tx->tm_isdst;
1841  tm->tm_gmtoff = tx->tm_gmtoff;
1842  tm->tm_zone = tx->tm_zone;
1843  *tzp = -tm->tm_gmtoff;
1844  if (tzn != NULL)
1845  *tzn = tm->tm_zone;
1846  }
1847  else
1848  {
1849  /*
1850  * When out of range of pg_time_t, treat as GMT
1851  */
1852  *tzp = 0;
1853  /* Mark this as *no* time zone available */
1854  tm->tm_isdst = -1;
1855  tm->tm_gmtoff = 0;
1856  tm->tm_zone = NULL;
1857  if (tzn != NULL)
1858  *tzn = NULL;
1859  }
1860 
1861  return 0;
1862 }
1863 
1864 
1865 /* tm2timestamp()
1866  * Convert a tm structure to a timestamp data type.
1867  * Note that year is _not_ 1900-based, but is an explicit full value.
1868  * Also, month is one-based, _not_ zero-based.
1869  *
1870  * Returns -1 on failure (value out of range).
1871  */
1872 int
1873 tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
1874 {
1875  TimeOffset date;
1876  TimeOffset time;
1877 
1878  /* Prevent overflow in Julian-day routines */
1879  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1880  {
1881  *result = 0; /* keep compiler quiet */
1882  return -1;
1883  }
1884 
1885  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1886  time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
1887 
1888  *result = date * USECS_PER_DAY + time;
1889  /* check for major overflow */
1890  if ((*result - time) / USECS_PER_DAY != date)
1891  {
1892  *result = 0; /* keep compiler quiet */
1893  return -1;
1894  }
1895  /* check for just-barely overflow (okay except time-of-day wraps) */
1896  /* caution: we want to allow 1999-12-31 24:00:00 */
1897  if ((*result < 0 && date > 0) ||
1898  (*result > 0 && date < -1))
1899  {
1900  *result = 0; /* keep compiler quiet */
1901  return -1;
1902  }
1903  if (tzp != NULL)
1904  *result = dt2local(*result, -(*tzp));
1905 
1906  /* final range check catches just-out-of-range timestamps */
1907  if (!IS_VALID_TIMESTAMP(*result))
1908  {
1909  *result = 0; /* keep compiler quiet */
1910  return -1;
1911  }
1912 
1913  return 0;
1914 }
1915 
1916 
1917 /* interval2tm()
1918  * Convert an interval data type to a tm structure.
1919  */
1920 int
1921 interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
1922 {
1923  TimeOffset time;
1924  TimeOffset tfrac;
1925 
1926  tm->tm_year = span.month / MONTHS_PER_YEAR;
1927  tm->tm_mon = span.month % MONTHS_PER_YEAR;
1928  tm->tm_mday = span.day;
1929  time = span.time;
1930 
1931  tfrac = time / USECS_PER_HOUR;
1932  time -= tfrac * USECS_PER_HOUR;
1933  tm->tm_hour = tfrac;
1934  if (!SAMESIGN(tm->tm_hour, tfrac))
1935  ereport(ERROR,
1936  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1937  errmsg("interval out of range")));
1938  tfrac = time / USECS_PER_MINUTE;
1939  time -= tfrac * USECS_PER_MINUTE;
1940  tm->tm_min = tfrac;
1941  tfrac = time / USECS_PER_SEC;
1942  *fsec = time - (tfrac * USECS_PER_SEC);
1943  tm->tm_sec = tfrac;
1944 
1945  return 0;
1946 }
1947 
1948 int
1949 tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
1950 {
1951  double total_months = (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
1952 
1953  if (total_months > INT_MAX || total_months < INT_MIN)
1954  return -1;
1955  span->month = total_months;
1956  span->day = tm->tm_mday;
1957  span->time = (((((tm->tm_hour * INT64CONST(60)) +
1958  tm->tm_min) * INT64CONST(60)) +
1959  tm->tm_sec) * USECS_PER_SEC) + fsec;
1960 
1961  return 0;
1962 }
1963 
1964 static TimeOffset
1965 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
1966 {
1967  return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
1968 }
1969 
1970 static Timestamp
1971 dt2local(Timestamp dt, int tz)
1972 {
1973  dt -= (tz * USECS_PER_SEC);
1974  return dt;
1975 }
1976 
1977 
1978 /*****************************************************************************
1979  * PUBLIC ROUTINES *
1980  *****************************************************************************/
1981 
1982 
1983 Datum
1985 {
1987 
1988  PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
1989 }
1990 
1991 Datum
1993 {
1994  PG_RETURN_BOOL(true);
1995 }
1996 
1997 
1998 /*----------------------------------------------------------
1999  * Relational operators for timestamp.
2000  *---------------------------------------------------------*/
2001 
2002 void
2004 {
2005  struct pg_tm *t0;
2006  pg_time_t epoch = 0;
2007 
2008  t0 = pg_gmtime(&epoch);
2009 
2010  if (t0 == NULL)
2011  elog(ERROR, "could not convert epoch to timestamp: %m");
2012 
2013  tm->tm_year = t0->tm_year;
2014  tm->tm_mon = t0->tm_mon;
2015  tm->tm_mday = t0->tm_mday;
2016  tm->tm_hour = t0->tm_hour;
2017  tm->tm_min = t0->tm_min;
2018  tm->tm_sec = t0->tm_sec;
2019 
2020  tm->tm_year += 1900;
2021  tm->tm_mon++;
2022 }
2023 
2024 Timestamp
2026 {
2027  Timestamp dt;
2028  struct pg_tm tt,
2029  *tm = &tt;
2030 
2031  GetEpochTime(tm);
2032  /* we don't bother to test for failure ... */
2033  tm2timestamp(tm, 0, NULL, &dt);
2034 
2035  return dt;
2036 } /* SetEpochTimestamp() */
2037 
2038 /*
2039  * We are currently sharing some code between timestamp and timestamptz.
2040  * The comparison functions are among them. - thomas 2001-09-25
2041  *
2042  * timestamp_relop - is timestamp1 relop timestamp2
2043  */
2044 int
2046 {
2047  return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2048 }
2049 
2050 Datum
2052 {
2053  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2054  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2055 
2056  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
2057 }
2058 
2059 Datum
2061 {
2062  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2063  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2064 
2065  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2066 }
2067 
2068 Datum
2070 {
2071  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2072  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2073 
2074  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2075 }
2076 
2077 Datum
2079 {
2080  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2081  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2082 
2083  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2084 }
2085 
2086 Datum
2088 {
2089  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2090  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2091 
2092  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2093 }
2094 
2095 Datum
2097 {
2098  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2099  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2100 
2101  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2102 }
2103 
2104 Datum
2106 {
2107  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2108  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2109 
2111 }
2112 
2113 /* note: this is used for timestamptz also */
2114 static int
2116 {
2119 
2120  return timestamp_cmp_internal(a, b);
2121 }
2122 
2123 Datum
2125 {
2127 
2128  ssup->comparator = timestamp_fastcmp;
2129  PG_RETURN_VOID();
2130 }
2131 
2132 Datum
2134 {
2135  return hashint8(fcinfo);
2136 }
2137 
2138 Datum
2140 {
2141  return hashint8extended(fcinfo);
2142 }
2143 
2144 /*
2145  * Cross-type comparison functions for timestamp vs timestamptz
2146  */
2147 
2148 Datum
2150 {
2151  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2153  TimestampTz dt1;
2154 
2155  dt1 = timestamp2timestamptz(timestampVal);
2156 
2157  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
2158 }
2159 
2160 Datum
2162 {
2163  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2165  TimestampTz dt1;
2166 
2167  dt1 = timestamp2timestamptz(timestampVal);
2168 
2169  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2170 }
2171 
2172 Datum
2174 {
2175  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2177  TimestampTz dt1;
2178 
2179  dt1 = timestamp2timestamptz(timestampVal);
2180 
2181  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2182 }
2183 
2184 Datum
2186 {
2187  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2189  TimestampTz dt1;
2190 
2191  dt1 = timestamp2timestamptz(timestampVal);
2192 
2193  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2194 }
2195 
2196 Datum
2198 {
2199  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2201  TimestampTz dt1;
2202 
2203  dt1 = timestamp2timestamptz(timestampVal);
2204 
2205  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2206 }
2207 
2208 Datum
2210 {
2211  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2213  TimestampTz dt1;
2214 
2215  dt1 = timestamp2timestamptz(timestampVal);
2216 
2217  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2218 }
2219 
2220 Datum
2222 {
2223  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2225  TimestampTz dt1;
2226 
2227  dt1 = timestamp2timestamptz(timestampVal);
2228 
2230 }
2231 
2232 Datum
2234 {
2236  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2237  TimestampTz dt2;
2238 
2239  dt2 = timestamp2timestamptz(timestampVal);
2240 
2241  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
2242 }
2243 
2244 Datum
2246 {
2248  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2249  TimestampTz dt2;
2250 
2251  dt2 = timestamp2timestamptz(timestampVal);
2252 
2253  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2254 }
2255 
2256 Datum
2258 {
2260  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2261  TimestampTz dt2;
2262 
2263  dt2 = timestamp2timestamptz(timestampVal);
2264 
2265  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2266 }
2267 
2268 Datum
2270 {
2272  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2273  TimestampTz dt2;
2274 
2275  dt2 = timestamp2timestamptz(timestampVal);
2276 
2277  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2278 }
2279 
2280 Datum
2282 {
2284  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2285  TimestampTz dt2;
2286 
2287  dt2 = timestamp2timestamptz(timestampVal);
2288 
2289  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2290 }
2291 
2292 Datum
2294 {
2296  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2297  TimestampTz dt2;
2298 
2299  dt2 = timestamp2timestamptz(timestampVal);
2300 
2301  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2302 }
2303 
2304 Datum
2306 {
2308  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2309  TimestampTz dt2;
2310 
2311  dt2 = timestamp2timestamptz(timestampVal);
2312 
2314 }
2315 
2316 
2317 /*
2318  * interval_relop - is interval1 relop interval2
2319  *
2320  * Interval comparison is based on converting interval values to a linear
2321  * representation expressed in the units of the time field (microseconds,
2322  * in the case of integer timestamps) with days assumed to be always 24 hours
2323  * and months assumed to be always 30 days. To avoid overflow, we need a
2324  * wider-than-int64 datatype for the linear representation, so use INT128.
2325  */
2326 
2327 static inline INT128
2329 {
2330  INT128 span;
2331  int64 dayfraction;
2332  int64 days;
2333 
2334  /*
2335  * Separate time field into days and dayfraction, then add the month and
2336  * day fields to the days part. We cannot overflow int64 days here.
2337  */
2338  dayfraction = interval->time % USECS_PER_DAY;
2339  days = interval->time / USECS_PER_DAY;
2340  days += interval->month * INT64CONST(30);
2341  days += interval->day;
2342 
2343  /* Widen dayfraction to 128 bits */
2344  span = int64_to_int128(dayfraction);
2345 
2346  /* Scale up days to microseconds, forming a 128-bit product */
2348 
2349  return span;
2350 }
2351 
2352 static int
2353 interval_cmp_internal(Interval *interval1, Interval *interval2)
2354 {
2355  INT128 span1 = interval_cmp_value(interval1);
2356  INT128 span2 = interval_cmp_value(interval2);
2357 
2358  return int128_compare(span1, span2);
2359 }
2360 
2361 Datum
2363 {
2364  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2365  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2366 
2367  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
2368 }
2369 
2370 Datum
2372 {
2373  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2374  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2375 
2376  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
2377 }
2378 
2379 Datum
2381 {
2382  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2383  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2384 
2385  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
2386 }
2387 
2388 Datum
2390 {
2391  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2392  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2393 
2394  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
2395 }
2396 
2397 Datum
2399 {
2400  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2401  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2402 
2403  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
2404 }
2405 
2406 Datum
2408 {
2409  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2410  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2411 
2412  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
2413 }
2414 
2415 Datum
2417 {
2418  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2419  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2420 
2421  PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
2422 }
2423 
2424 /*
2425  * Hashing for intervals
2426  *
2427  * We must produce equal hashvals for values that interval_cmp_internal()
2428  * considers equal. So, compute the net span the same way it does,
2429  * and then hash that.
2430  */
2431 Datum
2433 {
2435  INT128 span = interval_cmp_value(interval);
2436  int64 span64;
2437 
2438  /*
2439  * Use only the least significant 64 bits for hashing. The upper 64 bits
2440  * seldom add any useful information, and besides we must do it like this
2441  * for compatibility with hashes calculated before use of INT128 was
2442  * introduced.
2443  */
2444  span64 = int128_to_int64(span);
2445 
2447 }
2448 
2449 Datum
2451 {
2453  INT128 span = interval_cmp_value(interval);
2454  int64 span64;
2455 
2456  /* Same approach as interval_hash */
2457  span64 = int128_to_int64(span);
2458 
2460  PG_GETARG_DATUM(1));
2461 }
2462 
2463 /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
2464  *
2465  * Algorithm is per SQL spec. This is much harder than you'd think
2466  * because the spec requires us to deliver a non-null answer in some cases
2467  * where some of the inputs are null.
2468  */
2469 Datum
2471 {
2472  /*
2473  * The arguments are Timestamps, but we leave them as generic Datums to
2474  * avoid unnecessary conversions between value and reference forms --- not
2475  * to mention possible dereferences of null pointers.
2476  */
2477  Datum ts1 = PG_GETARG_DATUM(0);
2478  Datum te1 = PG_GETARG_DATUM(1);
2479  Datum ts2 = PG_GETARG_DATUM(2);
2480  Datum te2 = PG_GETARG_DATUM(3);
2481  bool ts1IsNull = PG_ARGISNULL(0);
2482  bool te1IsNull = PG_ARGISNULL(1);
2483  bool ts2IsNull = PG_ARGISNULL(2);
2484  bool te2IsNull = PG_ARGISNULL(3);
2485 
2486 #define TIMESTAMP_GT(t1,t2) \
2487  DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
2488 #define TIMESTAMP_LT(t1,t2) \
2489  DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
2490 
2491  /*
2492  * If both endpoints of interval 1 are null, the result is null (unknown).
2493  * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2494  * take ts1 as the lesser endpoint.
2495  */
2496  if (ts1IsNull)
2497  {
2498  if (te1IsNull)
2499  PG_RETURN_NULL();
2500  /* swap null for non-null */
2501  ts1 = te1;
2502  te1IsNull = true;
2503  }
2504  else if (!te1IsNull)
2505  {
2506  if (TIMESTAMP_GT(ts1, te1))
2507  {
2508  Datum tt = ts1;
2509 
2510  ts1 = te1;
2511  te1 = tt;
2512  }
2513  }
2514 
2515  /* Likewise for interval 2. */
2516  if (ts2IsNull)
2517  {
2518  if (te2IsNull)
2519  PG_RETURN_NULL();
2520  /* swap null for non-null */
2521  ts2 = te2;
2522  te2IsNull = true;
2523  }
2524  else if (!te2IsNull)
2525  {
2526  if (TIMESTAMP_GT(ts2, te2))
2527  {
2528  Datum tt = ts2;
2529 
2530  ts2 = te2;
2531  te2 = tt;
2532  }
2533  }
2534 
2535  /*
2536  * At this point neither ts1 nor ts2 is null, so we can consider three
2537  * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2538  */
2539  if (TIMESTAMP_GT(ts1, ts2))
2540  {
2541  /*
2542  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2543  * in the presence of nulls it's not quite completely so.
2544  */
2545  if (te2IsNull)
2546  PG_RETURN_NULL();
2547  if (TIMESTAMP_LT(ts1, te2))
2548  PG_RETURN_BOOL(true);
2549  if (te1IsNull)
2550  PG_RETURN_NULL();
2551 
2552  /*
2553  * If te1 is not null then we had ts1 <= te1 above, and we just found
2554  * ts1 >= te2, hence te1 >= te2.
2555  */
2556  PG_RETURN_BOOL(false);
2557  }
2558  else if (TIMESTAMP_LT(ts1, ts2))
2559  {
2560  /* This case is ts2 < te1 OR te2 < te1 */
2561  if (te1IsNull)
2562  PG_RETURN_NULL();
2563  if (TIMESTAMP_LT(ts2, te1))
2564  PG_RETURN_BOOL(true);
2565  if (te2IsNull)
2566  PG_RETURN_NULL();
2567 
2568  /*
2569  * If te2 is not null then we had ts2 <= te2 above, and we just found
2570  * ts2 >= te1, hence te2 >= te1.
2571  */
2572  PG_RETURN_BOOL(false);
2573  }
2574  else
2575  {
2576  /*
2577  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2578  * rather silly way of saying "true if both are non-null, else null".
2579  */
2580  if (te1IsNull || te2IsNull)
2581  PG_RETURN_NULL();
2582  PG_RETURN_BOOL(true);
2583  }
2584 
2585 #undef TIMESTAMP_GT
2586 #undef TIMESTAMP_LT
2587 }
2588 
2589 
2590 /*----------------------------------------------------------
2591  * "Arithmetic" operators on date/times.
2592  *---------------------------------------------------------*/
2593 
2594 Datum
2596 {
2597  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2598  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2599  Timestamp result;
2600 
2601  /* use timestamp_cmp_internal to be sure this agrees with comparisons */
2602  if (timestamp_cmp_internal(dt1, dt2) < 0)
2603  result = dt1;
2604  else
2605  result = dt2;
2606  PG_RETURN_TIMESTAMP(result);
2607 }
2608 
2609 Datum
2611 {
2612  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2613  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2614  Timestamp result;
2615 
2616  if (timestamp_cmp_internal(dt1, dt2) > 0)
2617  result = dt1;
2618  else
2619  result = dt2;
2620  PG_RETURN_TIMESTAMP(result);
2621 }
2622 
2623 
2624 Datum
2626 {
2627  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2628  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2629  Interval *result;
2630 
2631  result = (Interval *) palloc(sizeof(Interval));
2632 
2633  if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
2634  ereport(ERROR,
2635  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2636  errmsg("cannot subtract infinite timestamps")));
2637 
2638  result->time = dt1 - dt2;
2639 
2640  result->month = 0;
2641  result->day = 0;
2642 
2643  /*----------
2644  * This is wrong, but removing it breaks a lot of regression tests.
2645  * For example:
2646  *
2647  * test=> SET timezone = 'EST5EDT';
2648  * test=> SELECT
2649  * test-> ('2005-10-30 13:22:00-05'::timestamptz -
2650  * test(> '2005-10-29 13:22:00-04'::timestamptz);
2651  * ?column?
2652  * ----------------
2653  * 1 day 01:00:00
2654  * (1 row)
2655  *
2656  * so adding that to the first timestamp gets:
2657  *
2658  * test=> SELECT
2659  * test-> ('2005-10-29 13:22:00-04'::timestamptz +
2660  * test(> ('2005-10-30 13:22:00-05'::timestamptz -
2661  * test(> '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
2662  * timezone
2663  * --------------------
2664  * 2005-10-30 14:22:00
2665  * (1 row)
2666  *----------
2667  */
2669  IntervalPGetDatum(result)));
2670 
2671  PG_RETURN_INTERVAL_P(result);
2672 }
2673 
2674 /*
2675  * interval_justify_interval()
2676  *
2677  * Adjust interval so 'month', 'day', and 'time' portions are within
2678  * customary bounds. Specifically:
2679  *
2680  * 0 <= abs(time) < 24 hours
2681  * 0 <= abs(day) < 30 days
2682  *
2683  * Also, the sign bit on all three fields is made equal, so either
2684  * all three fields are negative or all are positive.
2685  */
2686 Datum
2688 {
2689  Interval *span = PG_GETARG_INTERVAL_P(0);
2690  Interval *result;
2691  TimeOffset wholeday;
2692  int32 wholemonth;
2693 
2694  result = (Interval *) palloc(sizeof(Interval));
2695  result->month = span->month;
2696  result->day = span->day;
2697  result->time = span->time;
2698 
2699  TMODULO(result->time, wholeday, USECS_PER_DAY);
2700  result->day += wholeday; /* could overflow... */
2701 
2702  wholemonth = result->day / DAYS_PER_MONTH;
2703  result->day -= wholemonth * DAYS_PER_MONTH;
2704  result->month += wholemonth;
2705 
2706  if (result->month > 0 &&
2707  (result->day < 0 || (result->day == 0 && result->time < 0)))
2708  {
2709  result->day += DAYS_PER_MONTH;
2710  result->month--;
2711  }
2712  else if (result->month < 0 &&
2713  (result->day > 0 || (result->day == 0 && result->time > 0)))
2714  {
2715  result->day -= DAYS_PER_MONTH;
2716  result->month++;
2717  }
2718 
2719  if (result->day > 0 && result->time < 0)
2720  {
2721  result->time += USECS_PER_DAY;
2722  result->day--;
2723  }
2724  else if (result->day < 0 && result->time > 0)
2725  {
2726  result->time -= USECS_PER_DAY;
2727  result->day++;
2728  }
2729 
2730  PG_RETURN_INTERVAL_P(result);
2731 }
2732 
2733 /*
2734  * interval_justify_hours()
2735  *
2736  * Adjust interval so 'time' contains less than a whole day, adding
2737  * the excess to 'day'. This is useful for
2738  * situations (such as non-TZ) where '1 day' = '24 hours' is valid,
2739  * e.g. interval subtraction and division.
2740  */
2741 Datum
2743 {
2744  Interval *span = PG_GETARG_INTERVAL_P(0);
2745  Interval *result;
2746  TimeOffset wholeday;
2747 
2748  result = (Interval *) palloc(sizeof(Interval));
2749  result->month = span->month;
2750  result->day = span->day;
2751  result->time = span->time;
2752 
2753  TMODULO(result->time, wholeday, USECS_PER_DAY);
2754  result->day += wholeday; /* could overflow... */
2755 
2756  if (result->day > 0 && result->time < 0)
2757  {
2758  result->time += USECS_PER_DAY;
2759  result->day--;
2760  }
2761  else if (result->day < 0 && result->time > 0)
2762  {
2763  result->time -= USECS_PER_DAY;
2764  result->day++;
2765  }
2766 
2767  PG_RETURN_INTERVAL_P(result);
2768 }
2769 
2770 /*
2771  * interval_justify_days()
2772  *
2773  * Adjust interval so 'day' contains less than 30 days, adding
2774  * the excess to 'month'.
2775  */
2776 Datum
2778 {
2779  Interval *span = PG_GETARG_INTERVAL_P(0);
2780  Interval *result;
2781  int32 wholemonth;
2782 
2783  result = (Interval *) palloc(sizeof(Interval));
2784  result->month = span->month;
2785  result->day = span->day;
2786  result->time = span->time;
2787 
2788  wholemonth = result->day / DAYS_PER_MONTH;
2789  result->day -= wholemonth * DAYS_PER_MONTH;
2790  result->month += wholemonth;
2791 
2792  if (result->month > 0 && result->day < 0)
2793  {
2794  result->day += DAYS_PER_MONTH;
2795  result->month--;
2796  }
2797  else if (result->month < 0 && result->day > 0)
2798  {
2799  result->day -= DAYS_PER_MONTH;
2800  result->month++;
2801  }
2802 
2803  PG_RETURN_INTERVAL_P(result);
2804 }
2805 
2806 /* timestamp_pl_interval()
2807  * Add an interval to a timestamp data type.
2808  * Note that interval has provisions for qualitative year/month and day
2809  * units, so try to do the right thing with them.
2810  * To add a month, increment the month, and use the same day of month.
2811  * Then, if the next month has fewer days, set the day of month
2812  * to the last day of month.
2813  * To add a day, increment the mday, and use the same time of day.
2814  * Lastly, add in the "quantitative time".
2815  */
2816 Datum
2818 {
2820  Interval *span = PG_GETARG_INTERVAL_P(1);
2821  Timestamp result;
2822 
2823  if (TIMESTAMP_NOT_FINITE(timestamp))
2824  result = timestamp;
2825  else
2826  {
2827  if (span->month != 0)
2828  {
2829  struct pg_tm tt,
2830  *tm = &tt;
2831  fsec_t fsec;
2832 
2833  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
2834  ereport(ERROR,
2835  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2836  errmsg("timestamp out of range")));
2837 
2838  tm->tm_mon += span->month;
2839  if (tm->tm_mon > MONTHS_PER_YEAR)
2840  {
2841  tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
2842  tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
2843  }
2844  else if (tm->tm_mon < 1)
2845  {
2846  tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
2848  }
2849 
2850  /* adjust for end of month boundary problems... */
2851  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2852  tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
2853 
2854  if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
2855  ereport(ERROR,
2856  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2857  errmsg("timestamp out of range")));
2858  }
2859 
2860  if (span->day != 0)
2861  {
2862  struct pg_tm tt,
2863  *tm = &tt;
2864  fsec_t fsec;
2865  int julian;
2866 
2867  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
2868  ereport(ERROR,
2869  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2870  errmsg("timestamp out of range")));
2871 
2872  /* Add days by converting to and from Julian */
2873  julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
2874  j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2875 
2876  if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
2877  ereport(ERROR,
2878  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2879  errmsg("timestamp out of range")));
2880  }
2881 
2882  timestamp += span->time;
2883 
2884  if (!IS_VALID_TIMESTAMP(timestamp))
2885  ereport(ERROR,
2886  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2887  errmsg("timestamp out of range")));
2888 
2889  result = timestamp;
2890  }
2891 
2892  PG_RETURN_TIMESTAMP(result);
2893 }
2894 
2895 Datum
2897 {
2899  Interval *span = PG_GETARG_INTERVAL_P(1);
2900  Interval tspan;
2901 
2902  tspan.month = -span->month;
2903  tspan.day = -span->day;
2904  tspan.time = -span->time;
2905 
2907  TimestampGetDatum(timestamp),
2908  PointerGetDatum(&tspan));
2909 }
2910 
2911 
2912 /* timestamptz_pl_interval()
2913  * Add an interval to a timestamp with time zone data type.
2914  * Note that interval has provisions for qualitative year/month
2915  * units, so try to do the right thing with them.
2916  * To add a month, increment the month, and use the same day of month.
2917  * Then, if the next month has fewer days, set the day of month
2918  * to the last day of month.
2919  * Lastly, add in the "quantitative time".
2920  */
2921 Datum
2923 {
2925  Interval *span = PG_GETARG_INTERVAL_P(1);
2926  TimestampTz result;
2927  int tz;
2928 
2929  if (TIMESTAMP_NOT_FINITE(timestamp))
2930  result = timestamp;
2931  else
2932  {
2933  if (span->month != 0)
2934  {
2935  struct pg_tm tt,
2936  *tm = &tt;
2937  fsec_t fsec;
2938 
2939  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2940  ereport(ERROR,
2941  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2942  errmsg("timestamp out of range")));
2943 
2944  tm->tm_mon += span->month;
2945  if (tm->tm_mon > MONTHS_PER_YEAR)
2946  {
2947  tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
2948  tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
2949  }
2950  else if (tm->tm_mon < 1)
2951  {
2952  tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
2954  }
2955 
2956  /* adjust for end of month boundary problems... */
2957  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2958  tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
2959 
2961 
2962  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
2963  ereport(ERROR,
2964  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2965  errmsg("timestamp out of range")));
2966  }
2967 
2968  if (span->day != 0)
2969  {
2970  struct pg_tm tt,
2971  *tm = &tt;
2972  fsec_t fsec;
2973  int julian;
2974 
2975  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2976  ereport(ERROR,
2977  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2978  errmsg("timestamp out of range")));
2979 
2980  /* Add days by converting to and from Julian */
2981  julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
2982  j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2983 
2985 
2986  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
2987  ereport(ERROR,
2988  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2989  errmsg("timestamp out of range")));
2990  }
2991 
2992  timestamp += span->time;
2993 
2994  if (!IS_VALID_TIMESTAMP(timestamp))
2995  ereport(ERROR,
2996  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2997  errmsg("timestamp out of range")));
2998 
2999  result = timestamp;
3000  }
3001 
3002  PG_RETURN_TIMESTAMP(result);
3003 }
3004 
3005 Datum
3007 {
3009  Interval *span = PG_GETARG_INTERVAL_P(1);
3010  Interval tspan;
3011 
3012  tspan.month = -span->month;
3013  tspan.day = -span->day;
3014  tspan.time = -span->time;
3015 
3017  TimestampGetDatum(timestamp),
3018  PointerGetDatum(&tspan));
3019 }
3020 
3021 
3022 Datum
3024 {
3026  Interval *result;
3027 
3028  result = (Interval *) palloc(sizeof(Interval));
3029 
3030  result->time = -interval->time;
3031  /* overflow check copied from int4um */
3032  if (interval->time != 0 && SAMESIGN(result->time, interval->time))
3033  ereport(ERROR,
3034  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3035  errmsg("interval out of range")));
3036  result->day = -interval->day;
3037  if (interval->day != 0 && SAMESIGN(result->day, interval->day))
3038  ereport(ERROR,
3039  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3040  errmsg("interval out of range")));
3041  result->month = -interval->month;
3042  if (interval->month != 0 && SAMESIGN(result->month, interval->month))
3043  ereport(ERROR,
3044  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3045  errmsg("interval out of range")));
3046 
3047  PG_RETURN_INTERVAL_P(result);
3048 }
3049 
3050 
3051 Datum
3053 {
3054  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3055  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3056  Interval *result;
3057 
3058  /* use interval_cmp_internal to be sure this agrees with comparisons */
3059  if (interval_cmp_internal(interval1, interval2) < 0)
3060  result = interval1;
3061  else
3062  result = interval2;
3063  PG_RETURN_INTERVAL_P(result);
3064 }
3065 
3066 Datum
3068 {
3069  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3070  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3071  Interval *result;
3072 
3073  if (interval_cmp_internal(interval1, interval2) > 0)
3074  result = interval1;
3075  else
3076  result = interval2;
3077  PG_RETURN_INTERVAL_P(result);
3078 }
3079 
3080 Datum
3082 {
3083  Interval *span1 = PG_GETARG_INTERVAL_P(0);
3084  Interval *span2 = PG_GETARG_INTERVAL_P(1);
3085  Interval *result;
3086 
3087  result = (Interval *) palloc(sizeof(Interval));
3088 
3089  result->month = span1->month + span2->month;
3090  /* overflow check copied from int4pl */
3091  if (SAMESIGN(span1->month, span2->month) &&
3092  !SAMESIGN(result->month, span1->month))
3093  ereport(ERROR,
3094  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3095  errmsg("interval out of range")));
3096 
3097  result->day = span1->day + span2->day;
3098  if (SAMESIGN(span1->day, span2->day) &&
3099  !SAMESIGN(result->day, span1->day))
3100  ereport(ERROR,
3101  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3102  errmsg("interval out of range")));
3103 
3104  result->time = span1->time + span2->time;
3105  if (SAMESIGN(span1->time, span2->time) &&
3106  !SAMESIGN(result->time, span1->time))
3107  ereport(ERROR,
3108  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3109  errmsg("interval out of range")));
3110 
3111  PG_RETURN_INTERVAL_P(result);
3112 }
3113 
3114 Datum
3116 {
3117  Interval *span1 = PG_GETARG_INTERVAL_P(0);
3118  Interval *span2 = PG_GETARG_INTERVAL_P(1);
3119  Interval *result;
3120 
3121  result = (Interval *) palloc(sizeof(Interval));
3122 
3123  result->month = span1->month - span2->month;
3124  /* overflow check copied from int4mi */
3125  if (!SAMESIGN(span1->month, span2->month) &&
3126  !SAMESIGN(result->month, span1->month))
3127  ereport(ERROR,
3128  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3129  errmsg("interval out of range")));
3130 
3131  result->day = span1->day - span2->day;
3132  if (!SAMESIGN(span1->day, span2->day) &&
3133  !SAMESIGN(result->day, span1->day))
3134  ereport(ERROR,
3135  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3136  errmsg("interval out of range")));
3137 
3138  result->time = span1->time - span2->time;
3139  if (!SAMESIGN(span1->time, span2->time) &&
3140  !SAMESIGN(result->time, span1->time))
3141  ereport(ERROR,
3142  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3143  errmsg("interval out of range")));
3144 
3145  PG_RETURN_INTERVAL_P(result);
3146 }
3147 
3148 /*
3149  * There is no interval_abs(): it is unclear what value to return:
3150  * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3151  * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3152  */
3153 
3154 Datum
3156 {
3157  Interval *span = PG_GETARG_INTERVAL_P(0);
3158  float8 factor = PG_GETARG_FLOAT8(1);
3159  double month_remainder_days,
3160  sec_remainder,
3161  result_double;
3162  int32 orig_month = span->month,
3163  orig_day = span->day;
3164  Interval *result;
3165 
3166  result = (Interval *) palloc(sizeof(Interval));
3167 
3168  result_double = span->month * factor;
3169  if (isnan(result_double) ||
3170  result_double > INT_MAX || result_double < INT_MIN)
3171  ereport(ERROR,
3172  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3173  errmsg("interval out of range")));
3174  result->month = (int32) result_double;
3175 
3176  result_double = span->day * factor;
3177  if (isnan(result_double) ||
3178  result_double > INT_MAX || result_double < INT_MIN)
3179  ereport(ERROR,
3180  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3181  errmsg("interval out of range")));
3182  result->day = (int32) result_double;
3183 
3184  /*
3185  * The above correctly handles the whole-number part of the month and day
3186  * products, but we have to do something with any fractional part
3187  * resulting when the factor is non-integral. We cascade the fractions
3188  * down to lower units using the conversion factors DAYS_PER_MONTH and
3189  * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
3190  * so by the representation. The user can choose to cascade up later,
3191  * using justify_hours and/or justify_days.
3192  */
3193 
3194  /*
3195  * Fractional months full days into days.
3196  *
3197  * Floating point calculation are inherently imprecise, so these
3198  * calculations are crafted to produce the most reliable result possible.
3199  * TSROUND() is needed to more accurately produce whole numbers where
3200  * appropriate.
3201  */
3202  month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
3203  month_remainder_days = TSROUND(month_remainder_days);
3204  sec_remainder = (orig_day * factor - result->day +
3205  month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3206  sec_remainder = TSROUND(sec_remainder);
3207 
3208  /*
3209  * Might have 24:00:00 hours due to rounding, or >24 hours because of time
3210  * cascade from months and days. It might still be >24 if the combination
3211  * of cascade and the seconds factor operation itself.
3212  */
3213  if (Abs(sec_remainder) >= SECS_PER_DAY)
3214  {
3215  result->day += (int) (sec_remainder / SECS_PER_DAY);
3216  sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3217  }
3218 
3219  /* cascade units down */
3220  result->day += (int32) month_remainder_days;
3221  result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
3222  if (result_double > PG_INT64_MAX || result_double < PG_INT64_MIN)
3223  ereport(ERROR,
3224  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3225  errmsg("interval out of range")));
3226  result->time = (int64) result_double;
3227 
3228  PG_RETURN_INTERVAL_P(result);
3229 }
3230 
3231 Datum
3233 {
3234  /* Args are float8 and Interval *, but leave them as generic Datum */
3235  Datum factor = PG_GETARG_DATUM(0);
3236  Datum span = PG_GETARG_DATUM(1);
3237 
3238  return DirectFunctionCall2(interval_mul, span, factor);
3239 }
3240 
3241 Datum
3243 {
3244  Interval *span = PG_GETARG_INTERVAL_P(0);
3245  float8 factor = PG_GETARG_FLOAT8(1);
3246  double month_remainder_days,
3247  sec_remainder;
3248  int32 orig_month = span->month,
3249  orig_day = span->day;
3250  Interval *result;
3251 
3252  result = (Interval *) palloc(sizeof(Interval));
3253 
3254  if (factor == 0.0)
3255  ereport(ERROR,
3256  (errcode(ERRCODE_DIVISION_BY_ZERO),
3257  errmsg("division by zero")));
3258 
3259  result->month = (int32) (span->month / factor);
3260  result->day = (int32) (span->day / factor);
3261 
3262  /*
3263  * Fractional months full days into days. See comment in interval_mul().
3264  */
3265  month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
3266  month_remainder_days = TSROUND(month_remainder_days);
3267  sec_remainder = (orig_day / factor - result->day +
3268  month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3269  sec_remainder = TSROUND(sec_remainder);
3270  if (Abs(sec_remainder) >= SECS_PER_DAY)
3271  {
3272  result->day += (int) (sec_remainder / SECS_PER_DAY);
3273  sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3274  }
3275 
3276  /* cascade units down */
3277  result->day += (int32) month_remainder_days;
3278  result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
3279 
3280  PG_RETURN_INTERVAL_P(result);
3281 }
3282 
3283 
3284 /*
3285  * in_range support functions for timestamps and intervals.
3286  *
3287  * Per SQL spec, we support these with interval as the offset type.
3288  * The spec's restriction that the offset not be negative is a bit hard to
3289  * decipher for intervals, but we choose to interpret it the same as our
3290  * interval comparison operators would.
3291  */
3292 
3293 Datum
3295 {
3298  Interval *offset = PG_GETARG_INTERVAL_P(2);
3299  bool sub = PG_GETARG_BOOL(3);
3300  bool less = PG_GETARG_BOOL(4);
3301  TimestampTz sum;
3302 
3303  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3304  ereport(ERROR,
3305  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3306  errmsg("invalid preceding or following size in window function")));
3307 
3308  /* We don't currently bother to avoid overflow hazards here */
3309  if (sub)
3311  TimestampTzGetDatum(base),
3312  IntervalPGetDatum(offset)));
3313  else
3315  TimestampTzGetDatum(base),
3316  IntervalPGetDatum(offset)));
3317 
3318  if (less)
3319  PG_RETURN_BOOL(val <= sum);
3320  else
3321  PG_RETURN_BOOL(val >= sum);
3322 }
3323 
3324 Datum
3326 {
3328  Timestamp base = PG_GETARG_TIMESTAMP(1);
3329  Interval *offset = PG_GETARG_INTERVAL_P(2);
3330  bool sub = PG_GETARG_BOOL(3);
3331  bool less = PG_GETARG_BOOL(4);
3332  Timestamp sum;
3333 
3334  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3335  ereport(ERROR,
3336  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3337  errmsg("invalid preceding or following size in window function")));
3338 
3339  /* We don't currently bother to avoid overflow hazards here */
3340  if (sub)
3342  TimestampGetDatum(base),
3343  IntervalPGetDatum(offset)));
3344  else
3346  TimestampGetDatum(base),
3347  IntervalPGetDatum(offset)));
3348 
3349  if (less)
3350  PG_RETURN_BOOL(val <= sum);
3351  else
3352  PG_RETURN_BOOL(val >= sum);
3353 }
3354 
3355 Datum
3357 {
3359  Interval *base = PG_GETARG_INTERVAL_P(1);
3360  Interval *offset = PG_GETARG_INTERVAL_P(2);
3361  bool sub = PG_GETARG_BOOL(3);
3362  bool less = PG_GETARG_BOOL(4);
3363  Interval *sum;
3364 
3365  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3366  ereport(ERROR,
3367  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3368  errmsg("invalid preceding or following size in window function")));
3369 
3370  /* We don't currently bother to avoid overflow hazards here */
3371  if (sub)
3373  IntervalPGetDatum(base),
3374  IntervalPGetDatum(offset)));
3375  else
3377  IntervalPGetDatum(base),
3378  IntervalPGetDatum(offset)));
3379 
3380  if (less)
3381  PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3382  else
3383  PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3384 }
3385 
3386 
3387 /*
3388  * interval_accum, interval_accum_inv, and interval_avg implement the
3389  * AVG(interval) aggregate.
3390  *
3391  * The transition datatype for this aggregate is a 2-element array of
3392  * intervals, where the first is the running sum and the second contains
3393  * the number of values so far in its 'time' field. This is a bit ugly
3394  * but it beats inventing a specialized datatype for the purpose.
3395  */
3396 
3397 Datum
3399 {
3400  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3402  Datum *transdatums;
3403  int ndatums;
3404  Interval sumX,
3405  N;
3406  Interval *newsum;
3407  ArrayType *result;
3408 
3409  deconstruct_array(transarray,
3410  INTERVALOID, sizeof(Interval), false, 'd',
3411  &transdatums, NULL, &ndatums);
3412  if (ndatums != 2)
3413  elog(ERROR, "expected 2-element interval array");
3414 
3415  sumX = *(DatumGetIntervalP(transdatums[0]));
3416  N = *(DatumGetIntervalP(transdatums[1]));
3417 
3419  IntervalPGetDatum(&sumX),
3420  IntervalPGetDatum(newval)));
3421  N.time += 1;
3422 
3423  transdatums[0] = IntervalPGetDatum(newsum);
3424  transdatums[1] = IntervalPGetDatum(&N);
3425 
3426  result = construct_array(transdatums, 2,
3427  INTERVALOID, sizeof(Interval), false, 'd');
3428 
3429  PG_RETURN_ARRAYTYPE_P(result);
3430 }
3431 
3432 Datum
3434 {
3435  ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
3436  ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
3437  Datum *transdatums1;
3438  Datum *transdatums2;
3439  int ndatums1;
3440  int ndatums2;
3441  Interval sum1,
3442  N1;
3443  Interval sum2,
3444  N2;
3445 
3446  Interval *newsum;
3447  ArrayType *result;
3448 
3449  deconstruct_array(transarray1,
3450  INTERVALOID, sizeof(Interval), false, 'd',
3451  &transdatums1, NULL, &ndatums1);
3452  if (ndatums1 != 2)
3453  elog(ERROR, "expected 2-element interval array");
3454 
3455  sum1 = *(DatumGetIntervalP(transdatums1[0]));
3456  N1 = *(DatumGetIntervalP(transdatums1[1]));
3457 
3458  deconstruct_array(transarray2,
3459  INTERVALOID, sizeof(Interval), false, 'd',
3460  &transdatums2, NULL, &ndatums2);
3461  if (ndatums2 != 2)
3462  elog(ERROR, "expected 2-element interval array");
3463 
3464  sum2 = *(DatumGetIntervalP(transdatums2[0]));
3465  N2 = *(DatumGetIntervalP(transdatums2[1]));
3466 
3468  IntervalPGetDatum(&sum1),
3469  IntervalPGetDatum(&sum2)));
3470  N1.time += N2.time;
3471 
3472  transdatums1[0] = IntervalPGetDatum(newsum);
3473  transdatums1[1] = IntervalPGetDatum(&N1);
3474 
3475  result = construct_array(transdatums1, 2,
3476  INTERVALOID, sizeof(Interval), false, 'd');
3477 
3478  PG_RETURN_ARRAYTYPE_P(result);
3479 }
3480 
3481 Datum
3483 {
3484  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3486  Datum *transdatums;
3487  int ndatums;
3488  Interval sumX,
3489  N;
3490  Interval *newsum;
3491  ArrayType *result;
3492 
3493  deconstruct_array(transarray,
3494  INTERVALOID, sizeof(Interval), false, 'd',
3495  &transdatums, NULL, &ndatums);
3496  if (ndatums != 2)
3497  elog(ERROR, "expected 2-element interval array");
3498 
3499  sumX = *(DatumGetIntervalP(transdatums[0]));
3500  N = *(DatumGetIntervalP(transdatums[1]));
3501 
3503  IntervalPGetDatum(&sumX),
3504  IntervalPGetDatum(newval)));
3505  N.time -= 1;
3506 
3507  transdatums[0] = IntervalPGetDatum(newsum);
3508  transdatums[1] = IntervalPGetDatum(&N);
3509 
3510  result = construct_array(transdatums, 2,
3511  INTERVALOID, sizeof(Interval), false, 'd');
3512 
3513  PG_RETURN_ARRAYTYPE_P(result);
3514 }
3515 
3516 Datum
3518 {
3519  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3520  Datum *transdatums;
3521  int ndatums;
3522  Interval sumX,
3523  N;
3524 
3525  deconstruct_array(transarray,
3526  INTERVALOID, sizeof(Interval), false, 'd',
3527  &transdatums, NULL, &ndatums);
3528  if (ndatums != 2)
3529  elog(ERROR, "expected 2-element interval array");
3530 
3531  sumX = *(DatumGetIntervalP(transdatums[0]));
3532  N = *(DatumGetIntervalP(transdatums[1]));
3533 
3534  /* SQL defines AVG of no values to be NULL */
3535  if (N.time == 0)
3536  PG_RETURN_NULL();
3537 
3539  IntervalPGetDatum(&sumX),
3540  Float8GetDatum((double) N.time));
3541 }
3542 
3543 
3544 /* timestamp_age()
3545  * Calculate time difference while retaining year/month fields.
3546  * Note that this does not result in an accurate absolute time span
3547  * since year and month are out of context once the arithmetic
3548  * is done.
3549  */
3550 Datum
3552 {
3553  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
3554  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
3555  Interval *result;
3556  fsec_t fsec,
3557  fsec1,
3558  fsec2;
3559  struct pg_tm tt,
3560  *tm = &tt;
3561  struct pg_tm tt1,
3562  *tm1 = &tt1;
3563  struct pg_tm tt2,
3564  *tm2 = &tt2;
3565 
3566  result = (Interval *) palloc(sizeof(Interval));
3567 
3568  if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
3569  timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
3570  {
3571  /* form the symbolic difference */
3572  fsec = fsec1 - fsec2;
3573  tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
3574  tm->tm_min = tm1->tm_min - tm2->tm_min;
3575  tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
3576  tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
3577  tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
3578  tm->tm_year = tm1->tm_year - tm2->tm_year;
3579 
3580  /* flip sign if necessary... */
3581  if (dt1 < dt2)
3582  {
3583  fsec = -fsec;
3584  tm->tm_sec = -tm->tm_sec;
3585  tm->tm_min = -tm->tm_min;
3586  tm->tm_hour = -tm->tm_hour;
3587  tm->tm_mday = -tm->tm_mday;
3588  tm->tm_mon = -tm->tm_mon;
3589  tm->tm_year = -tm->tm_year;
3590  }
3591 
3592  /* propagate any negative fields into the next higher field */
3593  while (fsec < 0)
3594  {
3595  fsec += USECS_PER_SEC;
3596  tm->tm_sec--;
3597  }
3598 
3599  while (tm->tm_sec < 0)
3600  {
3601  tm->tm_sec += SECS_PER_MINUTE;
3602  tm->tm_min--;
3603  }
3604 
3605  while (tm->tm_min < 0)
3606  {
3607  tm->tm_min += MINS_PER_HOUR;
3608  tm->tm_hour--;
3609  }
3610 
3611  while (tm->tm_hour < 0)
3612  {
3613  tm->tm_hour += HOURS_PER_DAY;
3614  tm->tm_mday--;
3615  }
3616 
3617  while (tm->tm_mday < 0)
3618  {
3619  if (dt1 < dt2)
3620  {
3621  tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
3622  tm->tm_mon--;
3623  }
3624  else
3625  {
3626  tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
3627  tm->tm_mon--;
3628  }
3629  }
3630 
3631  while (tm->tm_mon < 0)
3632  {
3633  tm->tm_mon += MONTHS_PER_YEAR;
3634  tm->tm_year--;
3635  }
3636 
3637  /* recover sign if necessary... */
3638  if (dt1 < dt2)
3639  {
3640  fsec = -fsec;
3641  tm->tm_sec = -tm->tm_sec;
3642  tm->tm_min = -tm->tm_min;
3643  tm->tm_hour = -tm->tm_hour;
3644  tm->tm_mday = -tm->tm_mday;
3645  tm->tm_mon = -tm->tm_mon;
3646  tm->tm_year = -tm->tm_year;
3647  }
3648 
3649  if (tm2interval(tm, fsec, result) != 0)
3650  ereport(ERROR,
3651  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3652  errmsg("interval out of range")));
3653  }
3654  else
3655  ereport(ERROR,
3656  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3657  errmsg("timestamp out of range")));
3658 
3659  PG_RETURN_INTERVAL_P(result);
3660 }
3661 
3662 
3663 /* timestamptz_age()
3664  * Calculate time difference while retaining year/month fields.
3665  * Note that this does not result in an accurate absolute time span
3666  * since year and month are out of context once the arithmetic
3667  * is done.
3668  */
3669 Datum
3671 {
3674  Interval *result;
3675  fsec_t fsec,
3676  fsec1,
3677  fsec2;
3678  struct pg_tm tt,
3679  *tm = &tt;
3680  struct pg_tm tt1,
3681  *tm1 = &tt1;
3682  struct pg_tm tt2,
3683  *tm2 = &tt2;
3684  int tz1;
3685  int tz2;
3686 
3687  result = (Interval *) palloc(sizeof(Interval));
3688 
3689  if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
3690  timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
3691  {
3692  /* form the symbolic difference */
3693  fsec = fsec1 - fsec2;
3694  tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
3695  tm->tm_min = tm1->tm_min - tm2->tm_min;
3696  tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
3697  tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
3698  tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
3699  tm->tm_year = tm1->tm_year - tm2->tm_year;
3700 
3701  /* flip sign if necessary... */
3702  if (dt1 < dt2)
3703  {
3704  fsec = -fsec;
3705  tm->tm_sec = -tm->tm_sec;
3706  tm->tm_min = -tm->tm_min;
3707  tm->tm_hour = -tm->tm_hour;
3708  tm->tm_mday = -tm->tm_mday;
3709  tm->tm_mon = -tm->tm_mon;
3710  tm->tm_year = -tm->tm_year;
3711  }
3712 
3713  /* propagate any negative fields into the next higher field */
3714  while (fsec < 0)
3715  {
3716  fsec += USECS_PER_SEC;
3717  tm->tm_sec--;
3718  }
3719 
3720  while (tm->tm_sec < 0)
3721  {
3722  tm->tm_sec += SECS_PER_MINUTE;
3723  tm->tm_min--;
3724  }
3725 
3726  while (tm->tm_min < 0)
3727  {
3728  tm->tm_min += MINS_PER_HOUR;
3729  tm->tm_hour--;
3730  }
3731 
3732  while (tm->tm_hour < 0)
3733  {
3734  tm->tm_hour += HOURS_PER_DAY;
3735  tm->tm_mday--;
3736  }
3737 
3738  while (tm->tm_mday < 0)
3739  {
3740  if (dt1 < dt2)
3741  {
3742  tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
3743  tm->tm_mon--;
3744  }
3745  else
3746  {
3747  tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
3748  tm->tm_mon--;
3749  }
3750  }
3751 
3752  while (tm->tm_mon < 0)
3753  {
3754  tm->tm_mon += MONTHS_PER_YEAR;
3755  tm->tm_year--;
3756  }
3757 
3758  /*
3759  * Note: we deliberately ignore any difference between tz1 and tz2.
3760  */
3761 
3762  /* recover sign if necessary... */
3763  if (dt1 < dt2)
3764  {
3765  fsec = -fsec;
3766  tm->tm_sec = -tm->tm_sec;
3767  tm->tm_min = -tm->tm_min;
3768  tm->tm_hour = -tm->tm_hour;
3769  tm->tm_mday = -tm->tm_mday;
3770  tm->tm_mon = -tm->tm_mon;
3771  tm->tm_year = -tm->tm_year;
3772  }
3773 
3774  if (tm2interval(tm, fsec, result) != 0)
3775  ereport(ERROR,
3776  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3777  errmsg("interval out of range")));
3778  }
3779  else
3780  ereport(ERROR,
3781  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3782  errmsg("timestamp out of range")));
3783 
3784  PG_RETURN_INTERVAL_P(result);
3785 }
3786 
3787 
3788 /*----------------------------------------------------------
3789  * Conversion operators.
3790  *---------------------------------------------------------*/
3791 
3792 
3793 /* timestamp_trunc()
3794  * Truncate timestamp to specified units.
3795  */
3796 Datum
3798 {
3799  text *units = PG_GETARG_TEXT_PP(0);
3801  Timestamp result;
3802  int type,
3803  val;
3804  char *lowunits;
3805  fsec_t fsec;
3806  struct pg_tm tt,
3807  *tm = &tt;
3808 
3809  if (TIMESTAMP_NOT_FINITE(timestamp))
3810  PG_RETURN_TIMESTAMP(timestamp);
3811 
3812  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3813  VARSIZE_ANY_EXHDR(units),
3814  false);
3815 
3816  type = DecodeUnits(0, lowunits, &val);
3817 
3818  if (type == UNITS)
3819  {
3820  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3821  ereport(ERROR,
3822  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3823  errmsg("timestamp out of range")));
3824 
3825  switch (val)
3826  {
3827  case DTK_WEEK:
3828  {
3829  int woy;
3830 
3831  woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
3832 
3833  /*
3834  * If it is week 52/53 and the month is January, then the
3835  * week must belong to the previous year. Also, some
3836  * December dates belong to the next year.
3837  */
3838  if (woy >= 52 && tm->tm_mon == 1)
3839  --tm->tm_year;
3840  if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
3841  ++tm->tm_year;
3842  isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
3843  tm->tm_hour = 0;
3844  tm->tm_min = 0;
3845  tm->tm_sec = 0;
3846  fsec = 0;
3847  break;
3848  }
3849  case DTK_MILLENNIUM:
3850  /* see comments in timestamptz_trunc */
3851  if (tm->tm_year > 0)
3852  tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
3853  else
3854  tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
3855  /* FALL THRU */
3856  case DTK_CENTURY:
3857  /* see comments in timestamptz_trunc */
3858  if (tm->tm_year > 0)
3859  tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
3860  else
3861  tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
3862  /* FALL THRU */
3863  case DTK_DECADE:
3864  /* see comments in timestamptz_trunc */
3865  if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
3866  {
3867  if (tm->tm_year > 0)
3868  tm->tm_year = (tm->tm_year / 10) * 10;
3869  else
3870  tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
3871  }
3872  /* FALL THRU */
3873  case DTK_YEAR:
3874  tm->tm_mon = 1;
3875  /* FALL THRU */
3876  case DTK_QUARTER:
3877  tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
3878  /* FALL THRU */
3879  case DTK_MONTH:
3880  tm->tm_mday = 1;
3881  /* FALL THRU */
3882  case DTK_DAY:
3883  tm->tm_hour = 0;
3884  /* FALL THRU */
3885  case DTK_HOUR:
3886  tm->tm_min = 0;
3887  /* FALL THRU */
3888  case DTK_MINUTE:
3889  tm->tm_sec = 0;
3890  /* FALL THRU */
3891  case DTK_SECOND:
3892  fsec = 0;
3893  break;
3894 
3895  case DTK_MILLISEC:
3896  fsec = (fsec / 1000) * 1000;
3897  break;
3898 
3899  case DTK_MICROSEC:
3900  break;
3901 
3902  default:
3903  ereport(ERROR,
3904  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3905  errmsg("timestamp units \"%s\" not supported",
3906  lowunits)));
3907  result = 0;
3908  }
3909 
3910  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
3911  ereport(ERROR,
3912  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3913  errmsg("timestamp out of range")));
3914  }
3915  else
3916  {
3917  ereport(ERROR,
3918  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3919  errmsg("timestamp units \"%s\" not recognized",
3920  lowunits)));
3921  result = 0;
3922  }
3923 
3924  PG_RETURN_TIMESTAMP(result);
3925 }
3926 
3927 /*
3928  * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
3929  *
3930  * tzp identifies the zone to truncate with respect to. We assume
3931  * infinite timestamps have already been rejected.
3932  */
3933 static TimestampTz
3935 {
3936  TimestampTz result;
3937  int tz;
3938  int type,
3939  val;
3940  bool redotz = false;
3941  char *lowunits;
3942  fsec_t fsec;
3943  struct pg_tm tt,
3944  *tm = &tt;
3945 
3946  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3947  VARSIZE_ANY_EXHDR(units),
3948  false);
3949 
3950  type = DecodeUnits(0, lowunits, &val);
3951 
3952  if (type == UNITS)
3953  {
3954  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
3955  ereport(ERROR,
3956  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3957  errmsg("timestamp out of range")));
3958 
3959  switch (val)
3960  {
3961  case DTK_WEEK:
3962  {
3963  int woy;
3964 
3965  woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
3966 
3967  /*
3968  * If it is week 52/53 and the month is January, then the
3969  * week must belong to the previous year. Also, some
3970  * December dates belong to the next year.
3971  */
3972  if (woy >= 52 && tm->tm_mon == 1)
3973  --tm->tm_year;
3974  if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
3975  ++tm->tm_year;
3976  isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
3977  tm->tm_hour = 0;
3978  tm->tm_min = 0;
3979  tm->tm_sec = 0;
3980  fsec = 0;
3981  redotz = true;
3982  break;
3983  }
3984  /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
3985  case DTK_MILLENNIUM:
3986 
3987  /*
3988  * truncating to the millennium? what is this supposed to
3989  * mean? let us put the first year of the millennium... i.e.
3990  * -1000, 1, 1001, 2001...
3991  */
3992  if (tm->tm_year > 0)
3993  tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
3994  else
3995  tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
3996  /* FALL THRU */
3997  case DTK_CENTURY:
3998  /* truncating to the century? as above: -100, 1, 101... */
3999  if (tm->tm_year > 0)
4000  tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4001  else
4002  tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4003  /* FALL THRU */
4004  case DTK_DECADE:
4005 
4006  /*
4007  * truncating to the decade? first year of the decade. must
4008  * not be applied if year was truncated before!
4009  */
4010  if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4011  {
4012  if (tm->tm_year > 0)
4013  tm->tm_year = (tm->tm_year / 10) * 10;
4014  else
4015  tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4016  }
4017  /* FALL THRU */
4018  case DTK_YEAR:
4019  tm->tm_mon = 1;
4020  /* FALL THRU */
4021  case DTK_QUARTER:
4022  tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4023  /* FALL THRU */
4024  case DTK_MONTH:
4025  tm->tm_mday = 1;
4026  /* FALL THRU */
4027  case DTK_DAY:
4028  tm->tm_hour = 0;
4029  redotz = true; /* for all cases >= DAY */
4030  /* FALL THRU */
4031  case DTK_HOUR:
4032  tm->tm_min = 0;
4033  /* FALL THRU */
4034  case DTK_MINUTE:
4035  tm->tm_sec = 0;
4036  /* FALL THRU */
4037  case DTK_SECOND:
4038  fsec = 0;
4039  break;
4040  case DTK_MILLISEC:
4041  fsec = (fsec / 1000) * 1000;
4042  break;
4043  case DTK_MICROSEC:
4044  break;
4045 
4046  default:
4047  ereport(ERROR,
4048  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4049  errmsg("timestamp with time zone units \"%s\" not "
4050  "supported", lowunits)));
4051  result = 0;
4052  }
4053 
4054  if (redotz)
4055  tz = DetermineTimeZoneOffset(tm, tzp);
4056 
4057  if (tm2timestamp(tm, fsec, &tz, &result) != 0)
4058  ereport(ERROR,
4059  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4060  errmsg("timestamp out of range")));
4061  }
4062  else
4063  {
4064  ereport(ERROR,
4065  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4066  errmsg("timestamp with time zone units \"%s\" not recognized",
4067  lowunits)));
4068  result = 0;
4069  }
4070 
4071  return result;
4072 }
4073 
4074 /* timestamptz_trunc()
4075  * Truncate timestamptz to specified units in session timezone.
4076  */
4077 Datum
4079 {
4080  text *units = PG_GETARG_TEXT_PP(0);
4082  TimestampTz result;
4083 
4084  if (TIMESTAMP_NOT_FINITE(timestamp))
4085  PG_RETURN_TIMESTAMPTZ(timestamp);
4086 
4087  result = timestamptz_trunc_internal(units, timestamp, session_timezone);
4088 
4089  PG_RETURN_TIMESTAMPTZ(result);
4090 }
4091 
4092 /* timestamptz_trunc_zone()
4093  * Truncate timestamptz to specified units in specified timezone.
4094  */
4095 Datum
4097 {
4098  text *units = PG_GETARG_TEXT_PP(0);
4100  text *zone = PG_GETARG_TEXT_PP(2);
4101  TimestampTz result;
4102  char tzname[TZ_STRLEN_MAX + 1];
4103  char *lowzone;
4104  int type,
4105  val;
4106  pg_tz *tzp;
4107 
4108  /*
4109  * timestamptz_zone() doesn't look up the zone for infinite inputs, so we
4110  * don't do so here either.
4111  */
4112  if (TIMESTAMP_NOT_FINITE(timestamp))
4113  PG_RETURN_TIMESTAMP(timestamp);
4114 
4115  /*
4116  * Look up the requested timezone (see notes in timestamptz_zone()).
4117  */
4118  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
4119 
4120  /* DecodeTimezoneAbbrev requires lowercase input */
4121  lowzone = downcase_truncate_identifier(tzname,
4122  strlen(tzname),
4123  false);
4124 
4125  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
4126 
4127  if (type == TZ || type == DTZ)
4128  {
4129  /* fixed-offset abbreviation, get a pg_tz descriptor for that */
4130  tzp = pg_tzset_offset(-val);
4131  }
4132  else if (type == DYNTZ)
4133  {
4134  /* dynamic-offset abbreviation, use its referenced timezone */
4135  }
4136  else
4137  {
4138  /* try it as a full zone name */
4139  tzp = pg_tzset(tzname);
4140  if (!tzp)
4141  ereport(ERROR,
4142  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4143  errmsg("time zone \"%s\" not recognized", tzname)));
4144  }
4145 
4146  result = timestamptz_trunc_internal(units, timestamp, tzp);
4147 
4148  PG_RETURN_TIMESTAMPTZ(result);
4149 }
4150 
4151 /* interval_trunc()
4152  * Extract specified field from interval.
4153  */
4154 Datum
4156 {
4157  text *units = PG_GETARG_TEXT_PP(0);
4159  Interval *result;
4160  int type,
4161  val;
4162  char *lowunits;
4163  fsec_t fsec;
4164  struct pg_tm tt,
4165  *tm = &tt;
4166 
4167  result = (Interval *) palloc(sizeof(Interval));
4168 
4169  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4170  VARSIZE_ANY_EXHDR(units),
4171  false);
4172 
4173  type = DecodeUnits(0, lowunits, &val);
4174 
4175  if (type == UNITS)
4176  {
4177  if (interval2tm(*interval, tm, &fsec) == 0)
4178  {
4179  switch (val)
4180  {
4181  case DTK_MILLENNIUM:
4182  /* caution: C division may have negative remainder */
4183  tm->tm_year = (tm->tm_year / 1000) * 1000;
4184  /* FALL THRU */
4185  case DTK_CENTURY:
4186  /* caution: C division may have negative remainder */
4187  tm->tm_year = (tm->tm_year / 100) * 100;
4188  /* FALL THRU */
4189  case DTK_DECADE:
4190  /* caution: C division may have negative remainder */
4191  tm->tm_year = (tm->tm_year / 10) * 10;
4192  /* FALL THRU */
4193  case DTK_YEAR:
4194  tm->tm_mon = 0;
4195  /* FALL THRU */
4196  case DTK_QUARTER:
4197  tm->tm_mon = 3 * (tm->tm_mon / 3);
4198  /* FALL THRU */
4199  case DTK_MONTH:
4200  tm->tm_mday = 0;
4201  /* FALL THRU */
4202  case DTK_DAY:
4203  tm->tm_hour = 0;
4204  /* FALL THRU */
4205  case DTK_HOUR:
4206  tm->tm_min = 0;
4207  /* FALL THRU */
4208  case DTK_MINUTE:
4209  tm->tm_sec = 0;
4210  /* FALL THRU */
4211  case DTK_SECOND:
4212  fsec = 0;
4213  break;
4214  case DTK_MILLISEC:
4215  fsec = (fsec / 1000) * 1000;
4216  break;
4217  case DTK_MICROSEC:
4218  break;
4219 
4220  default:
4221  if (val == DTK_WEEK)
4222  ereport(ERROR,
4223  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4224  errmsg("interval units \"%s\" not supported "
4225  "because months usually have fractional weeks",
4226  lowunits)));
4227  else
4228  ereport(ERROR,
4229  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4230  errmsg("interval units \"%s\" not supported",
4231  lowunits)));
4232  }
4233 
4234  if (tm2interval(tm, fsec, result) != 0)
4235  ereport(ERROR,
4236  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4237  errmsg("interval out of range")));
4238  }
4239  else
4240  elog(ERROR, "could not convert interval to tm");
4241  }
4242  else
4243  {
4244  ereport(ERROR,
4245  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4246  errmsg("interval units \"%s\" not recognized",
4247  lowunits)));
4248  }
4249 
4250  PG_RETURN_INTERVAL_P(result);
4251 }
4252 
4253 /* isoweek2j()
4254  *
4255  * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
4256  * Julian days are used to convert between ISO week dates and Gregorian dates.
4257  */
4258 int
4259 isoweek2j(int year, int week)
4260 {
4261  int day0,
4262  day4;
4263 
4264  /* fourth day of current year */
4265  day4 = date2j(year, 1, 4);
4266 
4267  /* day0 == offset to first day of week (Monday) */
4268  day0 = j2day(day4 - 1);
4269 
4270  return ((week - 1) * 7) + (day4 - day0);
4271 }
4272 
4273 /* isoweek2date()
4274  * Convert ISO week of year number to date.
4275  * The year field must be specified with the ISO year!
4276  * karel 2000/08/07
4277  */
4278 void
4279 isoweek2date(int woy, int *year, int *mon, int *mday)
4280 {
4281  j2date(isoweek2j(*year, woy), year, mon, mday);
4282 }
4283 
4284 /* isoweekdate2date()
4285  *
4286  * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
4287  * Gregorian day of week sent so weekday strings can be supplied.
4288  * Populates year, mon, and mday with the correct Gregorian values.
4289  * year must be passed in as the ISO year.
4290  */
4291 void
4292 isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
4293 {
4294  int jday;
4295 
4296  jday = isoweek2j(*year, isoweek);
4297  /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
4298  if (wday > 1)
4299  jday += wday - 2;
4300  else
4301  jday += 6;
4302  j2date(jday, year, mon, mday);
4303 }
4304 
4305 /* date2isoweek()
4306  *
4307  * Returns ISO week number of year.
4308  */
4309 int
4310 date2isoweek(int year, int mon, int mday)
4311 {
4312  float8 result;
4313  int day0,
4314  day4,
4315  dayn;
4316 
4317  /* current day */
4318  dayn = date2j(year, mon, mday);
4319 
4320  /* fourth day of current year */
4321  day4 = date2j(year, 1, 4);
4322 
4323  /* day0 == offset to first day of week (Monday) */
4324  day0 = j2day(day4 - 1);
4325 
4326  /*
4327  * We need the first week containing a Thursday, otherwise this day falls
4328  * into the previous year for purposes of counting weeks
4329  */
4330  if (dayn < day4 - day0)
4331  {
4332  day4 = date2j(year - 1, 1, 4);
4333 
4334  /* day0 == offset to first day of week (Monday) */
4335  day0 = j2day(day4 - 1);
4336  }
4337 
4338  result = (dayn - (day4 - day0)) / 7 + 1;
4339 
4340  /*
4341  * Sometimes the last few days in a year will fall into the first week of
4342  * the next year, so check for this.
4343  */
4344  if (result >= 52)
4345  {
4346  day4 = date2j(year + 1, 1, 4);
4347 
4348  /* day0 == offset to first day of week (Monday) */
4349  day0 = j2day(day4 - 1);
4350 
4351  if (dayn >= day4 - day0)
4352  result = (dayn - (day4 - day0)) / 7 + 1;
4353  }
4354 
4355  return (int) result;
4356 }
4357 
4358 
4359 /* date2isoyear()
4360  *
4361  * Returns ISO 8601 year number.
4362  */
4363 int
4364 date2isoyear(int year, int mon, int mday)
4365 {
4366  float8 result;
4367  int day0,
4368  day4,
4369  dayn;
4370 
4371  /* current day */
4372  dayn = date2j(year, mon, mday);
4373 
4374  /* fourth day of current year */
4375  day4 = date2j(year, 1, 4);
4376 
4377  /* day0 == offset to first day of week (Monday) */
4378  day0 = j2day(day4 - 1);
4379 
4380  /*
4381  * We need the first week containing a Thursday, otherwise this day falls
4382  * into the previous year for purposes of counting weeks
4383  */
4384  if (dayn < day4 - day0)
4385  {
4386  day4 = date2j(year - 1, 1, 4);
4387 
4388  /* day0 == offset to first day of week (Monday) */
4389  day0 = j2day(day4 - 1);
4390 
4391  year--;
4392  }
4393 
4394  result = (dayn - (day4 - day0)) / 7 + 1;
4395 
4396  /*
4397  * Sometimes the last few days in a year will fall into the first week of
4398  * the next year, so check for this.
4399  */
4400  if (result >= 52)
4401  {
4402  day4 = date2j(year + 1, 1, 4);
4403 
4404  /* day0 == offset to first day of week (Monday) */
4405  day0 = j2day(day4 - 1);
4406 
4407  if (dayn >= day4 - day0)
4408  year++;
4409  }
4410 
4411  return year;
4412 }
4413 
4414 
4415 /* date2isoyearday()
4416  *
4417  * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
4418  * Possible return values are 1 through 371 (364 in non-leap years).
4419  */
4420 int
4421 date2isoyearday(int year, int mon, int mday)
4422 {
4423  return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
4424 }
4425 
4426 /*
4427  * NonFiniteTimestampTzPart
4428  *
4429  * Used by timestamp_part and timestamptz_part when extracting from infinite
4430  * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
4431  * otherwise returns zero (which should be taken as meaning to return NULL).
4432  *
4433  * Errors thrown here for invalid units should exactly match those that
4434  * would be thrown in the calling functions, else there will be unexpected
4435  * discrepancies between finite- and infinite-input cases.
4436  */
4437 static float8
4438 NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
4439  bool isNegative, bool isTz)
4440 {
4441  if ((type != UNITS) && (type != RESERV))
4442  {
4443  if (isTz)
4444  ereport(ERROR,
4445  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4446  errmsg("timestamp with time zone units \"%s\" not recognized",
4447  lowunits)));
4448  else
4449  ereport(ERROR,
4450  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4451  errmsg("timestamp units \"%s\" not recognized",
4452  lowunits)));
4453  }
4454 
4455  switch (unit)
4456  {
4457  /* Oscillating units */
4458  case DTK_MICROSEC:
4459  case DTK_MILLISEC:
4460  case DTK_SECOND:
4461  case DTK_MINUTE:
4462  case DTK_HOUR:
4463  case DTK_DAY:
4464  case DTK_MONTH:
4465  case DTK_QUARTER:
4466  case DTK_WEEK:
4467  case DTK_DOW:
4468  case DTK_ISODOW:
4469  case DTK_DOY:
4470  case DTK_TZ:
4471  case DTK_TZ_MINUTE:
4472  case DTK_TZ_HOUR:
4473  return 0.0;
4474 
4475  /* Monotonically-increasing units */
4476  case DTK_YEAR:
4477  case DTK_DECADE:
4478  case DTK_CENTURY:
4479  case DTK_MILLENNIUM:
4480  case DTK_JULIAN:
4481  case DTK_ISOYEAR:
4482  case DTK_EPOCH:
4483  if (isNegative)
4484  return -get_float8_infinity();
4485  else
4486  return get_float8_infinity();
4487 
4488  default:
4489  if (isTz)
4490  ereport(ERROR,
4491  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4492  errmsg("timestamp with time zone units \"%s\" not supported",
4493  lowunits)));
4494  else
4495  ereport(ERROR,
4496  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4497  errmsg("timestamp units \"%s\" not supported",
4498  lowunits)));
4499  return 0.0; /* keep compiler quiet */
4500  }
4501 }
4502 
4503 /* timestamp_part()
4504  * Extract specified field from timestamp.
4505  */
4506 Datum
4508 {
4509  text *units = PG_GETARG_TEXT_PP(0);
4511  float8 result;
4512  Timestamp epoch;
4513  int type,
4514  val;
4515  char *lowunits;
4516  fsec_t fsec;
4517  struct pg_tm tt,
4518  *tm = &tt;
4519 
4520  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4521  VARSIZE_ANY_EXHDR(units),
4522  false);
4523 
4524  type = DecodeUnits(0, lowunits, &val);
4525  if (type == UNKNOWN_FIELD)
4526  type = DecodeSpecial(0, lowunits, &val);
4527 
4528  if (TIMESTAMP_NOT_FINITE(timestamp))
4529  {
4530  result = NonFiniteTimestampTzPart(type, val, lowunits,
4531  TIMESTAMP_IS_NOBEGIN(timestamp),
4532  false);
4533  if (result)
4534  PG_RETURN_FLOAT8(result);
4535  else
4536  PG_RETURN_NULL();
4537  }
4538 
4539  if (type == UNITS)
4540  {
4541  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4542  ereport(ERROR,
4543  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4544  errmsg("timestamp out of range")));
4545 
4546  switch (val)
4547  {
4548  case DTK_MICROSEC:
4549  result = tm->tm_sec * 1000000.0 + fsec;
4550  break;
4551 
4552  case DTK_MILLISEC:
4553  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4554  break;
4555 
4556  case DTK_SECOND:
4557  result = tm->tm_sec + fsec / 1000000.0;
4558  break;
4559 
4560  case DTK_MINUTE:
4561  result = tm->tm_min;
4562  break;
4563 
4564  case DTK_HOUR:
4565  result = tm->tm_hour;
4566  break;
4567 
4568  case DTK_DAY:
4569  result = tm->tm_mday;
4570  break;
4571 
4572  case DTK_MONTH:
4573  result = tm->tm_mon;
4574  break;
4575 
4576  case DTK_QUARTER:
4577  result = (tm->tm_mon - 1) / 3 + 1;
4578  break;
4579 
4580  case DTK_WEEK:
4581  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4582  break;
4583 
4584  case DTK_YEAR:
4585  if (tm->tm_year > 0)
4586  result = tm->tm_year;
4587  else
4588  /* there is no year 0, just 1 BC and 1 AD */
4589  result = tm->tm_year - 1;
4590  break;
4591 
4592  case DTK_DECADE:
4593 
4594  /*
4595  * what is a decade wrt dates? let us assume that decade 199
4596  * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
4597  * is 11 BC thru 2 BC...
4598  */
4599  if (tm->tm_year >= 0)
4600  result = tm->tm_year / 10;
4601  else
4602  result = -((8 - (tm->tm_year - 1)) / 10);
4603  break;
4604 
4605  case DTK_CENTURY:
4606 
4607  /* ----
4608  * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
4609  * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
4610  * there is no number 0 century.
4611  * ----
4612  */
4613  if (tm->tm_year > 0)
4614  result = (tm->tm_year + 99) / 100;
4615  else
4616  /* caution: C division may have negative remainder */
4617  result = -((99 - (tm->tm_year - 1)) / 100);
4618  break;
4619 
4620  case DTK_MILLENNIUM:
4621  /* see comments above. */
4622  if (tm->tm_year > 0)
4623  result = (tm->tm_year + 999) / 1000;
4624  else
4625  result = -((999 - (tm->tm_year - 1)) / 1000);
4626  break;
4627 
4628  case DTK_JULIAN:
4629  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4630  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4631  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4632  break;
4633 
4634  case DTK_ISOYEAR:
4635  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4636  break;
4637 
4638  case DTK_DOW:
4639  case DTK_ISODOW:
4640  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4641  ereport(ERROR,
4642  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4643  errmsg("timestamp out of range")));
4644  result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
4645  if (val == DTK_ISODOW && result == 0)
4646  result = 7;
4647  break;
4648 
4649  case DTK_DOY:
4650  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4651  ereport(ERROR,
4652  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4653  errmsg("timestamp out of range")));
4654  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4655  - date2j(tm->tm_year, 1, 1) + 1);
4656  break;
4657 
4658  case DTK_TZ:
4659  case DTK_TZ_MINUTE:
4660  case DTK_TZ_HOUR:
4661  default:
4662  ereport(ERROR,
4663  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4664  errmsg("timestamp units \"%s\" not supported",
4665  lowunits)));
4666  result = 0;
4667  }
4668  }
4669  else if (type == RESERV)
4670  {
4671  switch (val)
4672  {
4673  case DTK_EPOCH:
4674  epoch = SetEpochTimestamp();
4675  /* try to avoid precision loss in subtraction */
4676  if (timestamp < (PG_INT64_MAX + epoch))
4677  result = (timestamp - epoch) / 1000000.0;
4678  else
4679  result = ((float8) timestamp - epoch) / 1000000.0;
4680  break;
4681 
4682  default:
4683  ereport(ERROR,
4684  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4685  errmsg("timestamp units \"%s\" not supported",
4686  lowunits)));
4687  result = 0;
4688  }
4689 
4690  }
4691  else
4692  {
4693  ereport(ERROR,
4694  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4695  errmsg("timestamp units \"%s\" not recognized", lowunits)));
4696  result = 0;
4697  }
4698 
4699  PG_RETURN_FLOAT8(result);
4700 }
4701 
4702 /* timestamptz_part()
4703  * Extract specified field from timestamp with time zone.
4704  */
4705 Datum
4707 {
4708  text *units = PG_GETARG_TEXT_PP(0);
4710  float8 result;
4711  Timestamp epoch;
4712  int tz;
4713  int type,
4714  val;
4715  char *lowunits;
4716  double dummy;
4717  fsec_t fsec;
4718  struct pg_tm tt,
4719  *tm = &tt;
4720 
4721  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4722  VARSIZE_ANY_EXHDR(units),
4723  false);
4724 
4725  type = DecodeUnits(0, lowunits, &val);
4726  if (type == UNKNOWN_FIELD)
4727  type = DecodeSpecial(0, lowunits, &val);
4728 
4729  if (TIMESTAMP_NOT_FINITE(timestamp))
4730  {
4731  result = NonFiniteTimestampTzPart(type, val, lowunits,
4732  TIMESTAMP_IS_NOBEGIN(timestamp),
4733  true);
4734  if (result)
4735  PG_RETURN_FLOAT8(result);
4736  else
4737  PG_RETURN_NULL();
4738  }
4739 
4740  if (type == UNITS)
4741  {
4742  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4743  ereport(ERROR,
4744  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4745  errmsg("timestamp out of range")));
4746 
4747  switch (val)
4748  {
4749  case DTK_TZ:
4750  result = -tz;
4751  break;
4752 
4753  case DTK_TZ_MINUTE:
4754  result = -tz;
4755  result /= MINS_PER_HOUR;
4756  FMODULO(result, dummy, (double) MINS_PER_HOUR);
4757  break;
4758 
4759  case DTK_TZ_HOUR:
4760  dummy = -tz;
4761  FMODULO(dummy, result, (double) SECS_PER_HOUR);
4762  break;
4763 
4764  case DTK_MICROSEC:
4765  result = tm->tm_sec * 1000000.0 + fsec;
4766  break;
4767 
4768  case DTK_MILLISEC:
4769  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4770  break;
4771 
4772  case DTK_SECOND:
4773  result = tm->tm_sec + fsec / 1000000.0;
4774  break;
4775 
4776  case DTK_MINUTE:
4777  result = tm->tm_min;
4778  break;
4779 
4780  case DTK_HOUR:
4781  result = tm->tm_hour;
4782  break;
4783 
4784  case DTK_DAY:
4785  result = tm->tm_mday;
4786  break;
4787 
4788  case DTK_MONTH:
4789  result = tm->tm_mon;
4790  break;
4791 
4792  case DTK_QUARTER:
4793  result = (tm->tm_mon - 1) / 3 + 1;
4794  break;
4795 
4796  case DTK_WEEK:
4797  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4798  break;
4799 
4800  case DTK_YEAR:
4801  if (tm->tm_year > 0)
4802  result = tm->tm_year;
4803  else
4804  /* there is no year 0, just 1 BC and 1 AD */
4805  result = tm->tm_year - 1;
4806  break;
4807 
4808  case DTK_DECADE:
4809  /* see comments in timestamp_part */
4810  if (tm->tm_year > 0)
4811  result = tm->tm_year / 10;
4812  else
4813  result = -((8 - (tm->tm_year - 1)) / 10);
4814  break;
4815 
4816  case DTK_CENTURY:
4817  /* see comments in timestamp_part */
4818  if (tm->tm_year > 0)
4819  result = (tm->tm_year + 99) / 100;
4820  else
4821  result = -((99 - (tm->tm_year - 1)) / 100);
4822  break;
4823 
4824  case DTK_MILLENNIUM:
4825  /* see comments in timestamp_part */
4826  if (tm->tm_year > 0)
4827  result = (tm->tm_year + 999) / 1000;
4828  else
4829  result = -((999 - (tm->tm_year - 1)) / 1000);
4830  break;
4831 
4832  case DTK_JULIAN:
4833  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4834  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4835  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4836  break;
4837 
4838  case DTK_ISOYEAR:
4839  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4840  break;
4841 
4842  case DTK_DOW:
4843  case DTK_ISODOW:
4844  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4845  ereport(ERROR,
4846  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4847  errmsg("timestamp out of range")));
4848  result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
4849  if (val == DTK_ISODOW && result == 0)
4850  result = 7;
4851  break;
4852 
4853  case DTK_DOY:
4854  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4855  ereport(ERROR,
4856  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4857  errmsg("timestamp out of range")));
4858  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4859  - date2j(tm->tm_year, 1, 1) + 1);
4860  break;
4861 
4862  default:
4863  ereport(ERROR,
4864  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4865  errmsg("timestamp with time zone units \"%s\" not supported",
4866  lowunits)));
4867  result = 0;
4868  }
4869 
4870  }
4871  else if (type == RESERV)
4872  {
4873  switch (val)
4874  {
4875  case DTK_EPOCH:
4876  epoch = SetEpochTimestamp();
4877  /* try to avoid precision loss in subtraction */
4878  if (timestamp < (PG_INT64_MAX + epoch))
4879  result = (timestamp - epoch) / 1000000.0;
4880  else
4881  result = ((float8) timestamp - epoch) / 1000000.0;
4882  break;
4883 
4884  default:
4885  ereport(ERROR,
4886  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4887  errmsg("timestamp with time zone units \"%s\" not supported",
4888  lowunits)));
4889  result = 0;
4890  }
4891  }
4892  else
4893  {
4894  ereport(ERROR,
4895  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4896  errmsg("timestamp with time zone units \"%s\" not recognized",
4897  lowunits)));
4898 
4899  result = 0;
4900  }
4901 
4902  PG_RETURN_FLOAT8(result);
4903 }
4904 
4905 
4906 /* interval_part()
4907  * Extract specified field from interval.
4908  */
4909 Datum
4911 {
4912  text *units = PG_GETARG_TEXT_PP(0);
4914  float8 result;
4915  int type,
4916  val;
4917  char *lowunits;
4918  fsec_t fsec;
4919  struct pg_tm tt,
4920  *tm = &tt;
4921 
4922  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4923  VARSIZE_ANY_EXHDR(units),
4924  false);
4925 
4926  type = DecodeUnits(0, lowunits, &val);
4927  if (type == UNKNOWN_FIELD)
4928  type = DecodeSpecial(0, lowunits, &val);
4929 
4930  if (type == UNITS)
4931  {
4932  if (interval2tm(*interval, tm, &fsec) == 0)
4933  {
4934  switch (val)
4935  {
4936  case DTK_MICROSEC:
4937  result = tm->tm_sec * 1000000.0 + fsec;
4938  break;
4939 
4940  case DTK_MILLISEC:
4941  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4942  break;
4943 
4944  case DTK_SECOND:
4945  result = tm->tm_sec + fsec / 1000000.0;
4946  break;
4947 
4948  case DTK_MINUTE:
4949  result = tm->tm_min;
4950  break;
4951 
4952  case DTK_HOUR:
4953  result = tm->tm_hour;
4954  break;
4955 
4956  case DTK_DAY:
4957  result = tm->tm_mday;
4958  break;
4959 
4960  case DTK_MONTH:
4961  result = tm->tm_mon;
4962  break;
4963 
4964  case DTK_QUARTER:
4965  result = (tm->tm_mon / 3) + 1;
4966  break;
4967 
4968  case DTK_YEAR:
4969  result = tm->tm_year;
4970  break;
4971 
4972  case DTK_DECADE:
4973  /* caution: C division may have negative remainder */
4974  result = tm->tm_year / 10;
4975  break;
4976 
4977  case DTK_CENTURY:
4978  /* caution: C division may have negative remainder */
4979  result = tm->tm_year / 100;
4980  break;
4981 
4982  case DTK_MILLENNIUM:
4983  /* caution: C division may have negative remainder */
4984  result = tm->tm_year / 1000;
4985  break;
4986 
4987  default:
4988  ereport(ERROR,
4989  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4990  errmsg("interval units \"%s\" not supported",
4991  lowunits)));
4992  result = 0;
4993  }
4994 
4995  }
4996  else
4997  {
4998  elog(ERROR, "could not convert interval to tm");
4999  result = 0;
5000  }
5001  }
5002  else if (type == RESERV && val == DTK_EPOCH)
5003  {
5004  result = interval->time / 1000000.0;
5005  result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
5006  result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
5007  result += ((double) SECS_PER_DAY) * interval->day;
5008  }
5009  else
5010  {
5011  ereport(ERROR,
5012  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5013  errmsg("interval units \"%s\" not recognized",
5014  lowunits)));
5015  result = 0;
5016  }
5017 
5018  PG_RETURN_FLOAT8(result);
5019 }
5020 
5021 
5022 /* timestamp_zone()
5023  * Encode timestamp type with specified time zone.
5024  * This function is just timestamp2timestamptz() except instead of
5025  * shifting to the global timezone, we shift to the specified timezone.
5026  * This is different from the other AT TIME ZONE cases because instead
5027  * of shifting _to_ a new time zone, it sets the time to _be_ the
5028  * specified timezone.
5029  */
5030 Datum
5032 {
5033  text *zone = PG_GETARG_TEXT_PP(0);
5035  TimestampTz result;
5036  int tz;
5037  char tzname[TZ_STRLEN_MAX + 1];
5038  char *lowzone;
5039  int type,
5040  val;
5041  pg_tz *tzp;
5042  struct pg_tm tm;
5043  fsec_t fsec;
5044 
5045  if (TIMESTAMP_NOT_FINITE(timestamp))
5046  PG_RETURN_TIMESTAMPTZ(timestamp);
5047 
5048  /*
5049  * Look up the requested timezone. First we look in the timezone
5050  * abbreviation table (to handle cases like "EST"), and if that fails, we
5051  * look in the timezone database (to handle cases like
5052  * "America/New_York"). (This matches the order in which timestamp input
5053  * checks the cases; it's important because the timezone database unwisely
5054  * uses a few zone names that are identical to offset abbreviations.)
5055  */
5056  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5057 
5058  /* DecodeTimezoneAbbrev requires lowercase input */
5059  lowzone = downcase_truncate_identifier(tzname,
5060  strlen(tzname),
5061  false);
5062 
5063  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5064 
5065  if (type == TZ || type == DTZ)
5066  {
5067  /* fixed-offset abbreviation */
5068  tz = val;
5069  result = dt2local(timestamp, tz);
5070  }
5071  else if (type == DYNTZ)
5072  {
5073  /* dynamic-offset abbreviation, resolve using specified time */
5074  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5075  ereport(ERROR,
5076  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5077  errmsg("timestamp out of range")));
5078  tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
5079  result = dt2local(timestamp, tz);
5080  }
5081  else
5082  {
5083  /* try it as a full zone name */
5084  tzp = pg_tzset(tzname);
5085  if (tzp)
5086  {
5087  /* Apply the timezone change */
5088  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5089  ereport(ERROR,
5090  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5091  errmsg("timestamp out of range")));
5092  tz = DetermineTimeZoneOffset(&tm, tzp);
5093  if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
5094  ereport(ERROR,
5095  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5096  errmsg("timestamp out of range")));
5097  }
5098  else
5099  {
5100  ereport(ERROR,
5101  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5102  errmsg("time zone \"%s\" not recognized", tzname)));
5103  result = 0; /* keep compiler quiet */
5104  }
5105  }
5106 
5107  if (!IS_VALID_TIMESTAMP(result))
5108  ereport(ERROR,
5109  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5110  errmsg("timestamp out of range")));
5111 
5112  PG_RETURN_TIMESTAMPTZ(result);
5113 }
5114 
5115 /* timestamp_izone()
5116  * Encode timestamp type with specified time interval as time zone.
5117  */
5118 Datum
5120 {
5123  TimestampTz result;
5124  int tz;
5125 
5126  if (TIMESTAMP_NOT_FINITE(timestamp))
5127  PG_RETURN_TIMESTAMPTZ(timestamp);
5128 
5129  if (zone->month != 0 || zone->day != 0)
5130  ereport(ERROR,
5131  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5132  errmsg("interval time zone \"%s\" must not include months or days",
5134  PointerGetDatum(zone))))));
5135 
5136  tz = zone->time / USECS_PER_SEC;
5137 
5138  result = dt2local(timestamp, tz);
5139 
5140  if (!IS_VALID_TIMESTAMP(result))
5141  ereport(ERROR,
5142  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5143  errmsg("timestamp out of range")));
5144 
5145  PG_RETURN_TIMESTAMPTZ(result);
5146 } /* timestamp_izone() */
5147 
5148 /* TimestampTimestampTzRequiresRewrite()
5149  *
5150  * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
5151  * timestamptz_timestamp to be no-ops, where the return value has the same
5152  * bits as the argument. Since project convention is to assume a GUC changes
5153  * no more often than STABLE functions change, the answer is valid that long.
5154  */
5155 bool
5157 {
5158  long offset;
5159 
5160  if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
5161  return false;
5162  return true;
5163 }
5164 
5165 /* timestamp_timestamptz()
5166  * Convert local timestamp to timestamp at GMT
5167  */
5168 Datum
5170 {
5172 
5174 }
5175 
5176 static TimestampTz
5178 {
5179  TimestampTz result;
5180  struct pg_tm tt,
5181  *tm = &tt;
5182  fsec_t fsec;
5183  int tz;
5184 
5185  if (TIMESTAMP_NOT_FINITE(timestamp))
5186  result = timestamp;
5187  else
5188  {
5189  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
5190  ereport(ERROR,
5191  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5192  errmsg("timestamp out of range")));
5193 
5195 
5196  if (tm2timestamp(tm, fsec, &tz, &result) != 0)
5197  ereport(ERROR,
5198  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5199  errmsg("timestamp out of range")));
5200  }
5201 
5202  return result;
5203 }
5204 
5205 /* timestamptz_timestamp()
5206  * Convert timestamp at GMT to local timestamp
5207  */
5208 Datum
5210 {
5212 
5214 }
5215 
5216 static Timestamp
5218 {
5219  Timestamp result;
5220  struct pg_tm tt,
5221  *tm = &tt;
5222  fsec_t fsec;
5223  int tz;
5224 
5225  if (TIMESTAMP_NOT_FINITE(timestamp))
5226  result = timestamp;
5227  else
5228  {
5229  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5230  ereport(ERROR,
5231  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5232  errmsg("timestamp out of range")));
5233  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
5234  ereport(ERROR,
5235  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5236  errmsg("timestamp out of range")));
5237  }
5238  return result;
5239 }
5240 
5241 /* timestamptz_zone()
5242  * Evaluate timestamp with time zone type at the specified time zone.
5243  * Returns a timestamp without time zone.
5244  */
5245 Datum
5247 {
5248  text *zone = PG_GETARG_TEXT_PP(0);
5250  Timestamp result;
5251  int tz;
5252  char tzname[TZ_STRLEN_MAX + 1];
5253  char *lowzone;
5254  int type,
5255  val;
5256  pg_tz *tzp;
5257 
5258  if (TIMESTAMP_NOT_FINITE(timestamp))
5259  PG_RETURN_TIMESTAMP(timestamp);
5260 
5261  /*
5262  * Look up the requested timezone. First we look in the timezone
5263  * abbreviation table (to handle cases like "EST"), and if that fails, we
5264  * look in the timezone database (to handle cases like
5265  * "America/New_York"). (This matches the order in which timestamp input
5266  * checks the cases; it's important because the timezone database unwisely
5267  * uses a few zone names that are identical to offset abbreviations.)
5268  */
5269  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5270 
5271  /* DecodeTimezoneAbbrev requires lowercase input */
5272  lowzone = downcase_truncate_identifier(tzname,
5273  strlen(tzname),
5274  false);
5275 
5276  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5277 
5278  if (type == TZ || type == DTZ)
5279  {
5280  /* fixed-offset abbreviation */
5281  tz = -val;
5282  result = dt2local(timestamp, tz);
5283  }
5284  else if (type == DYNTZ)
5285  {
5286  /* dynamic-offset abbreviation, resolve using specified time */
5287  int isdst;
5288 
5289  tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
5290  result = dt2local(timestamp, tz);
5291  }
5292  else
5293  {
5294  /* try it as a full zone name */
5295  tzp = pg_tzset(tzname);
5296  if (tzp)
5297  {
5298  /* Apply the timezone change */
5299  struct pg_tm tm;
5300  fsec_t fsec;
5301 
5302  if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
5303  ereport(ERROR,
5304  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5305  errmsg("timestamp out of range")));
5306  if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
5307  ereport(ERROR,
5308  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5309  errmsg("timestamp out of range")));
5310  }
5311  else
5312  {
5313  ereport(ERROR,
5314  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5315  errmsg("time zone \"%s\" not recognized", tzname)));
5316  result = 0; /* keep compiler quiet */
5317  }
5318  }
5319 
5320  if (!IS_VALID_TIMESTAMP(result))
5321  ereport(ERROR,
5322  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5323  errmsg("timestamp out of range")));
5324 
5325  PG_RETURN_TIMESTAMP(result);
5326 }
5327 
5328 /* timestamptz_izone()
5329  * Encode timestamp with time zone type with specified time interval as time zone.
5330  * Returns a timestamp without time zone.
5331  */
5332 Datum
5334 {
5337  Timestamp result;
5338  int tz;
5339 
5340  if (TIMESTAMP_NOT_FINITE(timestamp))
5341  PG_RETURN_TIMESTAMP(timestamp);
5342 
5343  if (zone->month != 0 || zone->day != 0)
5344  ereport(ERROR,
5345  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5346  errmsg("interval time zone \"%s\" must not include months or days",
5348  PointerGetDatum(zone))))));
5349 
5350  tz = -(zone->time / USECS_PER_SEC);
5351 
5352  result = dt2local(timestamp, tz);
5353 
5354  if (!IS_VALID_TIMESTAMP(result))
5355  ereport(ERROR,
5356  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5357  errmsg("timestamp out of range")));
5358 
5359  PG_RETURN_TIMESTAMP(result);
5360 }
5361 
5362 /* generate_series_timestamp()
5363  * Generate the set of timestamps from start to finish by step
5364  */
5365 Datum
5367 {
5368  FuncCallContext *funcctx;
5370  Timestamp result;
5371 
5372  /* stuff done only on the first call of the function */
5373  if (SRF_IS_FIRSTCALL())
5374  {
5375  Timestamp start = PG_GETARG_TIMESTAMP(0);
5376  Timestamp finish = PG_GETARG_TIMESTAMP(1);
5377  Interval *step = PG_GETARG_INTERVAL_P(2);
5378  MemoryContext oldcontext;
5379  Interval interval_zero;
5380 
5381  /* create a function context for cross-call persistence */
5382  funcctx = SRF_FIRSTCALL_INIT();
5383 
5384  /*
5385  * switch to memory context appropriate for multiple function calls
5386  */
5387  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5388 
5389  /* allocate memory for user context */
5392 
5393  /*
5394  * Use fctx to keep state from call to call. Seed current with the
5395  * original start value
5396  */
5397  fctx->current = start;
5398  fctx->finish = finish;
5399  fctx->step = *step;
5400 
5401  /* Determine sign of the interval */
5402  MemSet(&interval_zero, 0, sizeof(Interval));
5403  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5404 
5405  if (fctx->step_sign == 0)
5406  ereport(ERROR,
5407  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5408  errmsg("step size cannot equal zero")));
5409 
5410  funcctx->user_fctx = fctx;
5411  MemoryContextSwitchTo(oldcontext);
5412  }
5413 
5414  /* stuff done on every call of the function */
5415  funcctx = SRF_PERCALL_SETUP();
5416 
5417  /*
5418  * get the saved state and use current as the result for this iteration
5419  */
5420  fctx = funcctx->user_fctx;
5421  result = fctx->current;
5422 
5423  if (fctx->step_sign > 0 ?
5424  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5425  timestamp_cmp_internal(result, fctx->finish) >= 0)
5426  {
5427  /* increment current in preparation for next iteration */
5428  fctx->current = DatumGetTimestamp(
5430  TimestampGetDatum(fctx->current),
5431  PointerGetDatum(&fctx->step)));
5432 
5433  /* do when there is more left to send */
5434  SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
5435  }
5436  else
5437  {
5438  /* do when there is no more left */
5439  SRF_RETURN_DONE(funcctx);
5440  }
5441 }
5442 
5443 /* generate_series_timestamptz()
5444  * Generate the set of timestamps from start to finish by step
5445  */
5446 Datum
5448 {
5449  FuncCallContext *funcctx;
5451  TimestampTz result;
5452 
5453  /* stuff done only on the first call of the function */
5454  if (SRF_IS_FIRSTCALL())
5455  {
5457  TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
5458  Interval *step = PG_GETARG_INTERVAL_P(2);
5459  MemoryContext oldcontext;
5460  Interval interval_zero;
5461 
5462  /* create a function context for cross-call persistence */
5463  funcctx = SRF_FIRSTCALL_INIT();
5464 
5465  /*
5466  * switch to memory context appropriate for multiple function calls
5467  */
5468  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5469 
5470  /* allocate memory for user context */
5473 
5474  /*
5475  * Use fctx to keep state from call to call. Seed current with the
5476  * original start value
5477  */
5478  fctx->current = start;
5479  fctx->finish = finish;
5480  fctx->step = *step;
5481 
5482  /* Determine sign of the interval */
5483  MemSet(&interval_zero, 0, sizeof(Interval));
5484  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5485 
5486  if (fctx->step_sign == 0)
5487  ereport(ERROR,
5488  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5489  errmsg("step size cannot equal zero")));
5490 
5491  funcctx->user_fctx = fctx;
5492  MemoryContextSwitchTo(oldcontext);
5493  }
5494 
5495  /* stuff done on every call of the function */
5496  funcctx = SRF_PERCALL_SETUP();
5497 
5498  /*
5499  * get the saved state and use current as the result for this iteration
5500  */
5501  fctx = funcctx->user_fctx;
5502  result = fctx->current;
5503 
5504  if (fctx->step_sign > 0 ?
5505  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5506  timestamp_cmp_internal(result, fctx->finish) >= 0)
5507  {
5508  /* increment current in preparation for next iteration */
5509  fctx->current = DatumGetTimestampTz(
5512  PointerGetDatum(&fctx->step)));
5513 
5514  /* do when there is more left to send */
5515  SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
5516  }
5517  else
5518  {
5519  /* do when there is no more left */
5520  SRF_RETURN_DONE(funcctx);
5521  }
5522 }
#define MAXDATELEN
Definition: datetime.h:201
static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec)
Definition: timestamp.c:1965
struct SortSupportData * SortSupport
Definition: sortsupport.h:58
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:276
Datum interval_smaller(PG_FUNCTION_ARGS)
Definition: timestamp.c:3052
Datum interval_justify_days(PG_FUNCTION_ARGS)
Definition: timestamp.c:2777
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
Datum in_range_interval_interval(PG_FUNCTION_ARGS)
Definition: timestamp.c:3356
size_t pg_strftime(char *s, size_t max, const char *format, const struct pg_tm *tm)
Definition: strftime.c:122
Datum interval_larger(PG_FUNCTION_ARGS)
Definition: timestamp.c:3067
#define TIMESTAMP_NOEND(j)
Definition: timestamp.h:117
static TimestampTz timestamp2timestamptz(Timestamp timestamp)
Definition: timestamp.c:5177
Datum timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
Definition: timestamp.c:2293
Datum make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
Definition: timestamp.c:666
#define DTERR_BAD_FORMAT
Definition: datetime.h:280
#define DTK_TZ_HOUR
Definition: datetime.h:178
#define PG_GETARG_INT32(n)
Definition: fmgr.h:264
#define DTK_CENTURY
Definition: datetime.h:170
#define PG_GETARG_INTERVAL_P(n)
Definition: timestamp.h:37
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
#define TIMESTAMP_END_JULIAN
Definition: timestamp.h:181
#define DAY
Definition: datetime.h:94
Datum timestamptz_send(PG_FUNCTION_ARGS)
Definition: timestamp.c:818
#define UNITS
Definition: datetime.h:108