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