PostgreSQL Source Code  git master
timestamp.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * timestamp.c
4  * Functions for the built-in SQL types "timestamp" and "interval".
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/adt/timestamp.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include <ctype.h>
19 #include <math.h>
20 #include <limits.h>
21 #include <sys/time.h>
22 
23 #include "access/xact.h"
24 #include "catalog/pg_type.h"
25 #include "common/int128.h"
26 #include "funcapi.h"
27 #include "libpq/pqformat.h"
28 #include "miscadmin.h"
29 #include "nodes/makefuncs.h"
30 #include "nodes/nodeFuncs.h"
31 #include "nodes/supportnodes.h"
32 #include "parser/scansup.h"
33 #include "utils/array.h"
34 #include "utils/builtins.h"
35 #include "utils/datetime.h"
36 #include "utils/float.h"
37 
38 /*
39  * gcc's -ffast-math switch breaks routines that expect exact results from
40  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
41  */
42 #ifdef __FAST_MATH__
43 #error -ffast-math is known to break this code
44 #endif
45 
46 #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
47 
48 /* Set at postmaster start */
50 
51 /* Set at configuration reload */
53 
54 typedef struct
55 {
59  int step_sign;
61 
62 typedef struct
63 {
67  int step_sign;
69 
70 
71 static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
72 static Timestamp dt2local(Timestamp dt, int timezone);
73 static void 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 (result_double > PG_INT64_MAX || result_double < PG_INT64_MIN)
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, 'd',
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, 'd');
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, 'd',
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, 'd',
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, 'd');
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, 'd',
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, 'd');
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, 'd',
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  */
4377 int
4378 date2isoyear(int year, int mon, int mday)
4379 {
4380  float8 result;
4381  int day0,
4382  day4,
4383  dayn;
4384 
4385  /* current day */
4386  dayn = date2j(year, mon, mday);
4387 
4388  /* fourth day of current year */
4389  day4 = date2j(year, 1, 4);
4390 
4391  /* day0 == offset to first day of week (Monday) */
4392  day0 = j2day(day4 - 1);
4393 
4394  /*
4395  * We need the first week containing a Thursday, otherwise this day falls
4396  * into the previous year for purposes of counting weeks
4397  */
4398  if (dayn < day4 - day0)
4399  {
4400  day4 = date2j(year - 1, 1, 4);
4401 
4402  /* day0 == offset to first day of week (Monday) */
4403  day0 = j2day(day4 - 1);
4404 
4405  year--;
4406  }
4407 
4408  result = (dayn - (day4 - day0)) / 7 + 1;
4409 
4410  /*
4411  * Sometimes the last few days in a year will fall into the first week of
4412  * the next year, so check for this.
4413  */
4414  if (result >= 52)
4415  {
4416  day4 = date2j(year + 1, 1, 4);
4417 
4418  /* day0 == offset to first day of week (Monday) */
4419  day0 = j2day(day4 - 1);
4420 
4421  if (dayn >= day4 - day0)
4422  year++;
4423  }
4424 
4425  return year;
4426 }
4427 
4428 
4429 /* date2isoyearday()
4430  *
4431  * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
4432  * Possible return values are 1 through 371 (364 in non-leap years).
4433  */
4434 int
4435 date2isoyearday(int year, int mon, int mday)
4436 {
4437  return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
4438 }
4439 
4440 /*
4441  * NonFiniteTimestampTzPart
4442  *
4443  * Used by timestamp_part and timestamptz_part when extracting from infinite
4444  * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
4445  * otherwise returns zero (which should be taken as meaning to return NULL).
4446  *
4447  * Errors thrown here for invalid units should exactly match those that
4448  * would be thrown in the calling functions, else there will be unexpected
4449  * discrepancies between finite- and infinite-input cases.
4450  */
4451 static float8
4452 NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
4453  bool isNegative, bool isTz)
4454 {
4455  if ((type != UNITS) && (type != RESERV))
4456  {
4457  if (isTz)
4458  ereport(ERROR,
4459  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4460  errmsg("timestamp with time zone units \"%s\" not recognized",
4461  lowunits)));
4462  else
4463  ereport(ERROR,
4464  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4465  errmsg("timestamp units \"%s\" not recognized",
4466  lowunits)));
4467  }
4468 
4469  switch (unit)
4470  {
4471  /* Oscillating units */
4472  case DTK_MICROSEC:
4473  case DTK_MILLISEC:
4474  case DTK_SECOND:
4475  case DTK_MINUTE:
4476  case DTK_HOUR:
4477  case DTK_DAY:
4478  case DTK_MONTH:
4479  case DTK_QUARTER:
4480  case DTK_WEEK:
4481  case DTK_DOW:
4482  case DTK_ISODOW:
4483  case DTK_DOY:
4484  case DTK_TZ:
4485  case DTK_TZ_MINUTE:
4486  case DTK_TZ_HOUR:
4487  return 0.0;
4488 
4489  /* Monotonically-increasing units */
4490  case DTK_YEAR:
4491  case DTK_DECADE:
4492  case DTK_CENTURY:
4493  case DTK_MILLENNIUM:
4494  case DTK_JULIAN:
4495  case DTK_ISOYEAR:
4496  case DTK_EPOCH:
4497  if (isNegative)
4498  return -get_float8_infinity();
4499  else
4500  return get_float8_infinity();
4501 
4502  default:
4503  if (isTz)
4504  ereport(ERROR,
4505  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4506  errmsg("timestamp with time zone units \"%s\" not supported",
4507  lowunits)));
4508  else
4509  ereport(ERROR,
4510  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4511  errmsg("timestamp units \"%s\" not supported",
4512  lowunits)));
4513  return 0.0; /* keep compiler quiet */
4514  }
4515 }
4516 
4517 /* timestamp_part()
4518  * Extract specified field from timestamp.
4519  */
4520 Datum
4522 {
4523  text *units = PG_GETARG_TEXT_PP(0);
4525  float8 result;
4526  Timestamp epoch;
4527  int type,
4528  val;
4529  char *lowunits;
4530  fsec_t fsec;
4531  struct pg_tm tt,
4532  *tm = &tt;
4533 
4534  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4535  VARSIZE_ANY_EXHDR(units),
4536  false);
4537 
4538  type = DecodeUnits(0, lowunits, &val);
4539  if (type == UNKNOWN_FIELD)
4540  type = DecodeSpecial(0, lowunits, &val);
4541 
4542  if (TIMESTAMP_NOT_FINITE(timestamp))
4543  {
4544  result = NonFiniteTimestampTzPart(type, val, lowunits,
4545  TIMESTAMP_IS_NOBEGIN(timestamp),
4546  false);
4547  if (result)
4548  PG_RETURN_FLOAT8(result);
4549  else
4550  PG_RETURN_NULL();
4551  }
4552 
4553  if (type == UNITS)
4554  {
4555  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4556  ereport(ERROR,
4557  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4558  errmsg("timestamp out of range")));
4559 
4560  switch (val)
4561  {
4562  case DTK_MICROSEC:
4563  result = tm->tm_sec * 1000000.0 + fsec;
4564  break;
4565 
4566  case DTK_MILLISEC:
4567  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4568  break;
4569 
4570  case DTK_SECOND:
4571  result = tm->tm_sec + fsec / 1000000.0;
4572  break;
4573 
4574  case DTK_MINUTE:
4575  result = tm->tm_min;
4576  break;
4577 
4578  case DTK_HOUR:
4579  result = tm->tm_hour;
4580  break;
4581 
4582  case DTK_DAY:
4583  result = tm->tm_mday;
4584  break;
4585 
4586  case DTK_MONTH:
4587  result = tm->tm_mon;
4588  break;
4589 
4590  case DTK_QUARTER:
4591  result = (tm->tm_mon - 1) / 3 + 1;
4592  break;
4593 
4594  case DTK_WEEK:
4595  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4596  break;
4597 
4598  case DTK_YEAR:
4599  if (tm->tm_year > 0)
4600  result = tm->tm_year;
4601  else
4602  /* there is no year 0, just 1 BC and 1 AD */
4603  result = tm->tm_year - 1;
4604  break;
4605 
4606  case DTK_DECADE:
4607 
4608  /*
4609  * what is a decade wrt dates? let us assume that decade 199
4610  * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
4611  * is 11 BC thru 2 BC...
4612  */
4613  if (tm->tm_year >= 0)
4614  result = tm->tm_year / 10;
4615  else
4616  result = -((8 - (tm->tm_year - 1)) / 10);
4617  break;
4618 
4619  case DTK_CENTURY:
4620 
4621  /* ----
4622  * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
4623  * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
4624  * there is no number 0 century.
4625  * ----
4626  */
4627  if (tm->tm_year > 0)
4628  result = (tm->tm_year + 99) / 100;
4629  else
4630  /* caution: C division may have negative remainder */
4631  result = -((99 - (tm->tm_year - 1)) / 100);
4632  break;
4633 
4634  case DTK_MILLENNIUM:
4635  /* see comments above. */
4636  if (tm->tm_year > 0)
4637  result = (tm->tm_year + 999) / 1000;
4638  else
4639  result = -((999 - (tm->tm_year - 1)) / 1000);
4640  break;
4641 
4642  case DTK_JULIAN:
4643  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4644  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4645  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4646  break;
4647 
4648  case DTK_ISOYEAR:
4649  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4650  break;
4651 
4652  case DTK_DOW:
4653  case DTK_ISODOW:
4654  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4655  ereport(ERROR,
4656  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4657  errmsg("timestamp out of range")));
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  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4665  ereport(ERROR,
4666  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4667  errmsg("timestamp out of range")));
4668  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4669  - date2j(tm->tm_year, 1, 1) + 1);
4670  break;
4671 
4672  case DTK_TZ:
4673  case DTK_TZ_MINUTE:
4674  case DTK_TZ_HOUR:
4675  default:
4676  ereport(ERROR,
4677  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4678  errmsg("timestamp units \"%s\" not supported",
4679  lowunits)));
4680  result = 0;
4681  }
4682  }
4683  else if (type == RESERV)
4684  {
4685  switch (val)
4686  {
4687  case DTK_EPOCH:
4688  epoch = SetEpochTimestamp();
4689  /* try to avoid precision loss in subtraction */
4690  if (timestamp < (PG_INT64_MAX + epoch))
4691  result = (timestamp - epoch) / 1000000.0;
4692  else
4693  result = ((float8) timestamp - epoch) / 1000000.0;
4694  break;
4695 
4696  default:
4697  ereport(ERROR,
4698  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4699  errmsg("timestamp units \"%s\" not supported",
4700  lowunits)));
4701  result = 0;
4702  }
4703 
4704  }
4705  else
4706  {
4707  ereport(ERROR,
4708  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4709  errmsg("timestamp units \"%s\" not recognized", lowunits)));
4710  result = 0;
4711  }
4712 
4713  PG_RETURN_FLOAT8(result);
4714 }
4715 
4716 /* timestamptz_part()
4717  * Extract specified field from timestamp with time zone.
4718  */
4719 Datum
4721 {
4722  text *units = PG_GETARG_TEXT_PP(0);
4724  float8 result;
4725  Timestamp epoch;
4726  int tz;
4727  int type,
4728  val;
4729  char *lowunits;
4730  double dummy;
4731  fsec_t fsec;
4732  struct pg_tm tt,
4733  *tm = &tt;
4734 
4735  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4736  VARSIZE_ANY_EXHDR(units),
4737  false);
4738 
4739  type = DecodeUnits(0, lowunits, &val);
4740  if (type == UNKNOWN_FIELD)
4741  type = DecodeSpecial(0, lowunits, &val);
4742 
4743  if (TIMESTAMP_NOT_FINITE(timestamp))
4744  {
4745  result = NonFiniteTimestampTzPart(type, val, lowunits,
4746  TIMESTAMP_IS_NOBEGIN(timestamp),
4747  true);
4748  if (result)
4749  PG_RETURN_FLOAT8(result);
4750  else
4751  PG_RETURN_NULL();
4752  }
4753 
4754  if (type == UNITS)
4755  {
4756  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4757  ereport(ERROR,
4758  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4759  errmsg("timestamp out of range")));
4760 
4761  switch (val)
4762  {
4763  case DTK_TZ:
4764  result = -tz;
4765  break;
4766 
4767  case DTK_TZ_MINUTE:
4768  result = -tz;
4769  result /= MINS_PER_HOUR;
4770  FMODULO(result, dummy, (double) MINS_PER_HOUR);
4771  break;
4772 
4773  case DTK_TZ_HOUR:
4774  dummy = -tz;
4775  FMODULO(dummy, result, (double) SECS_PER_HOUR);
4776  break;
4777 
4778  case DTK_MICROSEC:
4779  result = tm->tm_sec * 1000000.0 + fsec;
4780  break;
4781 
4782  case DTK_MILLISEC:
4783  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4784  break;
4785 
4786  case DTK_SECOND:
4787  result = tm->tm_sec + fsec / 1000000.0;
4788  break;
4789 
4790  case DTK_MINUTE:
4791  result = tm->tm_min;
4792  break;
4793 
4794  case DTK_HOUR:
4795  result = tm->tm_hour;
4796  break;
4797 
4798  case DTK_DAY:
4799  result = tm->tm_mday;
4800  break;
4801 
4802  case DTK_MONTH:
4803  result = tm->tm_mon;
4804  break;
4805 
4806  case DTK_QUARTER:
4807  result = (tm->tm_mon - 1) / 3 + 1;
4808  break;
4809 
4810  case DTK_WEEK:
4811  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4812  break;
4813 
4814  case DTK_YEAR:
4815  if (tm->tm_year > 0)
4816  result = tm->tm_year;
4817  else
4818  /* there is no year 0, just 1 BC and 1 AD */
4819  result = tm->tm_year - 1;
4820  break;
4821 
4822  case DTK_DECADE:
4823  /* see comments in timestamp_part */
4824  if (tm->tm_year > 0)
4825  result = tm->tm_year / 10;
4826  else
4827  result = -((8 - (tm->tm_year - 1)) / 10);
4828  break;
4829 
4830  case DTK_CENTURY:
4831  /* see comments in timestamp_part */
4832  if (tm->tm_year > 0)
4833  result = (tm->tm_year + 99) / 100;
4834  else
4835  result = -((99 - (tm->tm_year - 1)) / 100);
4836  break;
4837 
4838  case DTK_MILLENNIUM:
4839  /* see comments in timestamp_part */
4840  if (tm->tm_year > 0)
4841  result = (tm->tm_year + 999) / 1000;
4842  else
4843  result = -((999 - (tm->tm_year - 1)) / 1000);
4844  break;
4845 
4846  case DTK_JULIAN:
4847  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4848  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4849  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4850  break;
4851 
4852  case DTK_ISOYEAR:
4853  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4854  break;
4855 
4856  case DTK_DOW:
4857  case DTK_ISODOW:
4858  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4859  ereport(ERROR,
4860  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4861  errmsg("timestamp out of range")));
4862  result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
4863  if (val == DTK_ISODOW && result == 0)
4864  result = 7;
4865  break;
4866 
4867  case DTK_DOY:
4868  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4869  ereport(ERROR,
4870  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4871  errmsg("timestamp out of range")));
4872  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4873  - date2j(tm->tm_year, 1, 1) + 1);
4874  break;
4875 
4876  default:
4877  ereport(ERROR,
4878  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4879  errmsg("timestamp with time zone units \"%s\" not supported",
4880  lowunits)));
4881  result = 0;
4882  }
4883 
4884  }
4885  else if (type == RESERV)
4886  {
4887  switch (val)
4888  {
4889  case DTK_EPOCH:
4890  epoch = SetEpochTimestamp();
4891  /* try to avoid precision loss in subtraction */
4892  if (timestamp < (PG_INT64_MAX + epoch))
4893  result = (timestamp - epoch) / 1000000.0;
4894  else
4895  result = ((float8) timestamp - epoch) / 1000000.0;
4896  break;
4897 
4898  default:
4899  ereport(ERROR,
4900  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4901  errmsg("timestamp with time zone units \"%s\" not supported",
4902  lowunits)));
4903  result = 0;
4904  }
4905  }
4906  else
4907  {
4908  ereport(ERROR,
4909  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4910  errmsg("timestamp with time zone units \"%s\" not recognized",
4911  lowunits)));
4912 
4913  result = 0;
4914  }
4915 
4916  PG_RETURN_FLOAT8(result);
4917 }
4918 
4919 
4920 /* interval_part()
4921  * Extract specified field from interval.
4922  */
4923 Datum
4925 {
4926  text *units = PG_GETARG_TEXT_PP(0);
4928  float8 result;
4929  int type,
4930  val;
4931  char *lowunits;
4932  fsec_t fsec;
4933  struct pg_tm tt,
4934  *tm = &tt;
4935 
4936  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4937  VARSIZE_ANY_EXHDR(units),
4938  false);
4939 
4940  type = DecodeUnits(0, lowunits, &val);
4941  if (type == UNKNOWN_FIELD)
4942  type = DecodeSpecial(0, lowunits, &val);
4943 
4944  if (type == UNITS)
4945  {
4946  if (interval2tm(*interval, tm, &fsec) == 0)
4947  {
4948  switch (val)
4949  {
4950  case DTK_MICROSEC:
4951  result = tm->tm_sec * 1000000.0 + fsec;
4952  break;
4953 
4954  case DTK_MILLISEC:
4955  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4956  break;
4957 
4958  case DTK_SECOND:
4959  result = tm->tm_sec + fsec / 1000000.0;
4960  break;
4961 
4962  case DTK_MINUTE:
4963  result = tm->tm_min;
4964  break;
4965 
4966  case DTK_HOUR:
4967  result = tm->tm_hour;
4968  break;
4969 
4970  case DTK_DAY:
4971  result = tm->tm_mday;
4972  break;
4973 
4974  case DTK_MONTH:
4975  result = tm->tm_mon;
4976  break;
4977 
4978  case DTK_QUARTER:
4979  result = (tm->tm_mon / 3) + 1;
4980  break;
4981 
4982  case DTK_YEAR:
4983  result = tm->tm_year;
4984  break;
4985 
4986  case DTK_DECADE:
4987  /* caution: C division may have negative remainder */
4988  result = tm->tm_year / 10;
4989  break;
4990 
4991  case DTK_CENTURY:
4992  /* caution: C division may have negative remainder */
4993  result = tm->tm_year / 100;
4994  break;
4995 
4996  case DTK_MILLENNIUM:
4997  /* caution: C division may have negative remainder */
4998  result = tm->tm_year / 1000;
4999  break;
5000 
5001  default:
5002  ereport(ERROR,
5003  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5004  errmsg("interval units \"%s\" not supported",
5005  lowunits)));
5006  result = 0;
5007  }
5008 
5009  }
5010  else
5011  {
5012  elog(ERROR, "could not convert interval to tm");
5013  result = 0;
5014  }
5015  }
5016  else if (type == RESERV && val == DTK_EPOCH)
5017  {
5018  result = interval->time / 1000000.0;
5019  result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
5020  result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
5021  result += ((double) SECS_PER_DAY) * interval->day;
5022  }
5023  else
5024  {
5025  ereport(ERROR,
5026  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5027  errmsg("interval units \"%s\" not recognized",
5028  lowunits)));
5029  result = 0;
5030  }
5031 
5032  PG_RETURN_FLOAT8(result);
5033 }
5034 
5035 
5036 /* timestamp_zone()
5037  * Encode timestamp type with specified time zone.
5038  * This function is just timestamp2timestamptz() except instead of
5039  * shifting to the global timezone, we shift to the specified timezone.
5040  * This is different from the other AT TIME ZONE cases because instead
5041  * of shifting _to_ a new time zone, it sets the time to _be_ the
5042  * specified timezone.
5043  */
5044 Datum
5046 {
5047  text *zone = PG_GETARG_TEXT_PP(0);
5049  TimestampTz result;
5050  int tz;
5051  char tzname[TZ_STRLEN_MAX + 1];
5052  char *lowzone;
5053  int type,
5054  val;
5055  pg_tz *tzp;
5056  struct pg_tm tm;
5057  fsec_t fsec;
5058 
5059  if (TIMESTAMP_NOT_FINITE(timestamp))
5060  PG_RETURN_TIMESTAMPTZ(timestamp);
5061 
5062  /*
5063  * Look up the requested timezone. First we look in the timezone
5064  * abbreviation table (to handle cases like "EST"), and if that fails, we
5065  * look in the timezone database (to handle cases like
5066  * "America/New_York"). (This matches the order in which timestamp input
5067  * checks the cases; it's important because the timezone database unwisely
5068  * uses a few zone names that are identical to offset abbreviations.)
5069  */
5070  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5071 
5072  /* DecodeTimezoneAbbrev requires lowercase input */
5073  lowzone = downcase_truncate_identifier(tzname,
5074  strlen(tzname),
5075  false);
5076 
5077  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5078 
5079  if (type == TZ || type == DTZ)
5080  {
5081  /* fixed-offset abbreviation */
5082  tz = val;
5083  result = dt2local(timestamp, tz);
5084  }
5085  else if (type == DYNTZ)
5086  {
5087  /* dynamic-offset abbreviation, resolve using specified time */
5088  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5089  ereport(ERROR,
5090  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5091  errmsg("timestamp out of range")));
5092  tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
5093  result = dt2local(timestamp, tz);
5094  }
5095  else
5096  {
5097  /* try it as a full zone name */
5098  tzp = pg_tzset(tzname);
5099  if (tzp)
5100  {
5101  /* Apply the timezone change */
5102  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5103  ereport(ERROR,
5104  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5105  errmsg("timestamp out of range")));
5106  tz = DetermineTimeZoneOffset(&tm, tzp);
5107  if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
5108  ereport(ERROR,
5109  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5110  errmsg("timestamp out of range")));
5111  }
5112  else
5113  {
5114  ereport(ERROR,
5115  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5116  errmsg("time zone \"%s\" not recognized", tzname)));
5117  result = 0; /* keep compiler quiet */
5118  }
5119  }
5120 
5121  if (!IS_VALID_TIMESTAMP(result))
5122  ereport(ERROR,
5123  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5124  errmsg("timestamp out of range")));
5125 
5126  PG_RETURN_TIMESTAMPTZ(result);
5127 }
5128 
5129 /* timestamp_izone()
5130  * Encode timestamp type with specified time interval as time zone.
5131  */
5132 Datum
5134 {
5137  TimestampTz result;
5138  int tz;
5139 
5140  if (TIMESTAMP_NOT_FINITE(timestamp))
5141  PG_RETURN_TIMESTAMPTZ(timestamp);
5142 
5143  if (zone->month != 0 || zone->day != 0)
5144  ereport(ERROR,
5145  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5146  errmsg("interval time zone \"%s\" must not include months or days",
5148  PointerGetDatum(zone))))));
5149 
5150  tz = zone->time / USECS_PER_SEC;
5151 
5152  result = dt2local(timestamp, tz);
5153 
5154  if (!IS_VALID_TIMESTAMP(result))
5155  ereport(ERROR,
5156  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5157  errmsg("timestamp out of range")));
5158 
5159  PG_RETURN_TIMESTAMPTZ(result);
5160 } /* timestamp_izone() */
5161 
5162 /* TimestampTimestampTzRequiresRewrite()
5163  *
5164  * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
5165  * timestamptz_timestamp to be no-ops, where the return value has the same
5166  * bits as the argument. Since project convention is to assume a GUC changes
5167  * no more often than STABLE functions change, the answer is valid that long.
5168  */
5169 bool
5171 {
5172  long offset;
5173 
5174  if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
5175  return false;
5176  return true;
5177 }
5178 
5179 /* timestamp_timestamptz()
5180  * Convert local timestamp to timestamp at GMT
5181  */
5182 Datum
5184 {
5186 
5188 }
5189 
5190 /*
5191  * Convert timestamp to timestamp with time zone.
5192  *
5193  * If 'have_error' is NULL, then errors are thrown, else '*have_error' is set
5194  * and zero is returned.
5195  */
5196 
5199 {
5200  TimestampTz result;
5201  struct pg_tm tt,
5202  *tm = &tt;
5203  fsec_t fsec;
5204  int tz;
5205 
5206  if (TIMESTAMP_NOT_FINITE(timestamp))
5207  return timestamp;
5208 
5209  if (!timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL))
5210  {
5212 
5213  if (!tm2timestamp(tm, fsec, &tz, &result))
5214  return result;
5215  }
5216 
5217  if (have_error)
5218  *have_error = true;
5219  else
5220  ereport(ERROR,
5221  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5222  errmsg("timestamp out of range")));
5223 
5224  return 0;
5225 }
5226 
5227 /*
5228  * Single-argument version of timestamp2timestamptz_opt_error().
5229  */
5230 static TimestampTz
5232 {
5233  return timestamp2timestamptz_opt_error(timestamp, NULL);
5234 }
5235 
5236 /* timestamptz_timestamp()
5237  * Convert timestamp at GMT to local timestamp
5238  */
5239 Datum
5241 {
5243 
5245 }
5246 
5247 static Timestamp
5249 {
5250  Timestamp result;
5251  struct pg_tm tt,
5252  *tm = &tt;
5253  fsec_t fsec;
5254  int tz;
5255 
5256  if (TIMESTAMP_NOT_FINITE(timestamp))
5257  result = timestamp;
5258  else
5259  {
5260  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5261  ereport(ERROR,
5262  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5263  errmsg("timestamp out of range")));
5264  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
5265  ereport(ERROR,
5266  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5267  errmsg("timestamp out of range")));
5268  }
5269  return result;
5270 }
5271 
5272 /* timestamptz_zone()
5273  * Evaluate timestamp with time zone type at the specified time zone.
5274  * Returns a timestamp without time zone.
5275  */
5276 Datum
5278 {
5279  text *zone = PG_GETARG_TEXT_PP(0);
5281  Timestamp result;
5282  int tz;
5283  char tzname[TZ_STRLEN_MAX + 1];
5284  char *lowzone;
5285  int type,
5286  val;
5287  pg_tz *tzp;
5288 
5289  if (TIMESTAMP_NOT_FINITE(timestamp))
5290  PG_RETURN_TIMESTAMP(timestamp);
5291 
5292  /*
5293  * Look up the requested timezone. First we look in the timezone
5294  * abbreviation table (to handle cases like "EST"), and if that fails, we
5295  * look in the timezone database (to handle cases like
5296  * "America/New_York"). (This matches the order in which timestamp input
5297  * checks the cases; it's important because the timezone database unwisely
5298  * uses a few zone names that are identical to offset abbreviations.)
5299  */
5300  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5301 
5302  /* DecodeTimezoneAbbrev requires lowercase input */
5303  lowzone = downcase_truncate_identifier(tzname,
5304  strlen(tzname),
5305  false);
5306 
5307  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5308 
5309  if (type == TZ || type == DTZ)
5310  {
5311  /* fixed-offset abbreviation */
5312  tz = -val;
5313  result = dt2local(timestamp, tz);
5314  }
5315  else if (type == DYNTZ)
5316  {
5317  /* dynamic-offset abbreviation, resolve using specified time */
5318  int isdst;
5319 
5320  tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
5321  result = dt2local(timestamp, tz);
5322  }
5323  else
5324  {
5325  /* try it as a full zone name */
5326  tzp = pg_tzset(tzname);
5327  if (tzp)
5328  {
5329  /* Apply the timezone change */
5330  struct pg_tm tm;
5331  fsec_t fsec;
5332 
5333  if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
5334  ereport(ERROR,
5335  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5336  errmsg("timestamp out of range")));
5337  if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
5338  ereport(ERROR,
5339  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5340  errmsg("timestamp out of range")));
5341  }
5342  else
5343  {
5344  ereport(ERROR,
5345  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5346  errmsg("time zone \"%s\" not recognized", tzname)));
5347  result = 0; /* keep compiler quiet */
5348  }
5349  }
5350 
5351  if (!IS_VALID_TIMESTAMP(result))
5352  ereport(ERROR,
5353  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5354  errmsg("timestamp out of range")));
5355 
5356  PG_RETURN_TIMESTAMP(result);
5357 }
5358 
5359 /* timestamptz_izone()
5360  * Encode timestamp with time zone type with specified time interval as time zone.
5361  * Returns a timestamp without time zone.
5362  */
5363 Datum
5365 {
5368  Timestamp result;
5369  int tz;
5370 
5371  if (TIMESTAMP_NOT_FINITE(timestamp))
5372  PG_RETURN_TIMESTAMP(timestamp);
5373 
5374  if (zone->month != 0 || zone->day != 0)
5375  ereport(ERROR,
5376  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5377  errmsg("interval time zone \"%s\" must not include months or days",
5379  PointerGetDatum(zone))))));
5380 
5381  tz = -(zone->time / USECS_PER_SEC);
5382 
5383  result = dt2local(timestamp, tz);
5384 
5385  if (!IS_VALID_TIMESTAMP(result))
5386  ereport(ERROR,
5387  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5388  errmsg("timestamp out of range")));
5389 
5390  PG_RETURN_TIMESTAMP(result);
5391 }
5392 
5393 /* generate_series_timestamp()
5394  * Generate the set of timestamps from start to finish by step
5395  */
5396 Datum
5398 {
5399  FuncCallContext *funcctx;
5401  Timestamp result;
5402 
5403  /* stuff done only on the first call of the function */
5404  if (SRF_IS_FIRSTCALL())
5405  {
5406  Timestamp start = PG_GETARG_TIMESTAMP(0);
5407  Timestamp finish = PG_GETARG_TIMESTAMP(1);
5408  Interval *step = PG_GETARG_INTERVAL_P(2);
5409  MemoryContext oldcontext;
5410  Interval interval_zero;
5411 
5412  /* create a function context for cross-call persistence */
5413  funcctx = SRF_FIRSTCALL_INIT();
5414 
5415  /*
5416  * switch to memory context appropriate for multiple function calls
5417  */
5418  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5419 
5420  /* allocate memory for user context */
5423 
5424  /*
5425  * Use fctx to keep state from call to call. Seed current with the
5426  * original start value
5427  */
5428  fctx->current = start;
5429  fctx->finish = finish;
5430  fctx->step = *step;
5431 
5432  /* Determine sign of the interval */
5433  MemSet(&interval_zero, 0, sizeof(Interval));
5434  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5435 
5436  if (fctx->step_sign == 0)
5437  ereport(ERROR,
5438  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5439  errmsg("step size cannot equal zero")));
5440 
5441  funcctx->user_fctx = fctx;
5442  MemoryContextSwitchTo(oldcontext);
5443  }
5444 
5445  /* stuff done on every call of the function */
5446  funcctx = SRF_PERCALL_SETUP();
5447 
5448  /*
5449  * get the saved state and use current as the result for this iteration
5450  */
5451  fctx = funcctx->user_fctx;
5452  result = fctx->current;
5453 
5454  if (fctx->step_sign > 0 ?
5455  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5456  timestamp_cmp_internal(result, fctx->finish) >= 0)
5457  {
5458  /* increment current in preparation for next iteration */
5459  fctx->current = DatumGetTimestamp(
5461  TimestampGetDatum(fctx->current),
5462  PointerGetDatum(&fctx->step)));
5463 
5464  /* do when there is more left to send */
5465  SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
5466  }
5467  else
5468  {
5469  /* do when there is no more left */
5470  SRF_RETURN_DONE(funcctx);
5471  }
5472 }
5473 
5474 /* generate_series_timestamptz()
5475  * Generate the set of timestamps from start to finish by step
5476  */
5477 Datum
5479 {
5480  FuncCallContext *funcctx;
5482  TimestampTz result;
5483 
5484  /* stuff done only on the first call of the function */
5485  if (SRF_IS_FIRSTCALL())
5486  {
5488  TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
5489  Interval *step = PG_GETARG_INTERVAL_P(2);
5490  MemoryContext oldcontext;
5491  Interval interval_zero;
5492 
5493  /* create a function context for cross-call persistence */
5494  funcctx = SRF_FIRSTCALL_INIT();
5495 
5496  /*
5497  * switch to memory context appropriate for multiple function calls
5498  */
5499  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5500 
5501  /* allocate memory for user context */
5504 
5505  /*
5506  * Use fctx to keep state from call to call. Seed current with the
5507  * original start value
5508  */
5509  fctx->current = start;
5510  fctx->finish = finish;
5511  fctx->step = *step;
5512 
5513  /* Determine sign of the interval */
5514  MemSet(&interval_zero, 0, sizeof(Interval));
5515  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5516 
5517  if (fctx->step_sign == 0)
5518  ereport(ERROR,
5519  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5520  errmsg("step size cannot equal zero")));
5521 
5522  funcctx->user_fctx = fctx;
5523  MemoryContextSwitchTo(oldcontext);
5524  }
5525 
5526  /* stuff done on every call of the function */
5527  funcctx = SRF_PERCALL_SETUP();
5528 
5529  /*
5530  * get the saved state and use current as the result for this iteration
5531  */
5532  fctx = funcctx->user_fctx;
5533  result = fctx->current;
5534 
5535  if (fctx->step_sign > 0 ?
5536  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5537  timestamp_cmp_internal(result, fctx->finish) >= 0)
5538  {
5539  /* increment current in preparation for next iteration */
5540  fctx->current = DatumGetTimestampTz(
5543  PointerGetDatum(&fctx->step)));
5544 
5545  /* do when there is more left to send */
5546  SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
5547  }
5548  else
5549  {
5550  /* do when there is no more left */
5551  SRF_RETURN_DONE(funcctx);
5552  }
5553 }
#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:351
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:5231
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: