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