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