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