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-2021, 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  * This is typically used to calculate a wait timeout for select(2),
1645  * which explains the otherwise-odd choice of output format.
1646  *
1647  * Both inputs must be ordinary finite timestamps (in current usage,
1648  * they'll be results from GetCurrentTimestamp()).
1649  *
1650  * We expect start_time <= stop_time. If not, we return zeros,
1651  * since then we're already past the previously determined stop_time.
1652  */
1653 void
1655  long *secs, int *microsecs)
1656 {
1657  TimestampTz diff = stop_time - start_time;
1658 
1659  if (diff <= 0)
1660  {
1661  *secs = 0;
1662  *microsecs = 0;
1663  }
1664  else
1665  {
1666  *secs = (long) (diff / USECS_PER_SEC);
1667  *microsecs = (int) (diff % USECS_PER_SEC);
1668  }
1669 }
1670 
1671 /*
1672  * TimestampDifferenceMilliseconds -- convert the difference between two
1673  * timestamps into integer milliseconds
1674  *
1675  * This is typically used to calculate a wait timeout for WaitLatch()
1676  * or a related function. The choice of "long" as the result type
1677  * is to harmonize with that. It is caller's responsibility that the
1678  * input timestamps not be so far apart as to risk overflow of "long"
1679  * (which'd happen at about 25 days on machines with 32-bit "long").
1680  *
1681  * Both inputs must be ordinary finite timestamps (in current usage,
1682  * they'll be results from GetCurrentTimestamp()).
1683  *
1684  * We expect start_time <= stop_time. If not, we return zero,
1685  * since then we're already past the previously determined stop_time.
1686  *
1687  * Note we round up any fractional millisecond, since waiting for just
1688  * less than the intended timeout is undesirable.
1689  */
1690 long
1692 {
1693  TimestampTz diff = stop_time - start_time;
1694 
1695  if (diff <= 0)
1696  return 0;
1697  else
1698  return (long) ((diff + 999) / 1000);
1699 }
1700 
1701 /*
1702  * TimestampDifferenceExceeds -- report whether the difference between two
1703  * timestamps is >= a threshold (expressed in milliseconds)
1704  *
1705  * Both inputs must be ordinary finite timestamps (in current usage,
1706  * they'll be results from GetCurrentTimestamp()).
1707  */
1708 bool
1710  TimestampTz stop_time,
1711  int msec)
1712 {
1713  TimestampTz diff = stop_time - start_time;
1714 
1715  return (diff >= msec * INT64CONST(1000));
1716 }
1717 
1718 /*
1719  * Convert a time_t to TimestampTz.
1720  *
1721  * We do not use time_t internally in Postgres, but this is provided for use
1722  * by functions that need to interpret, say, a stat(2) result.
1723  *
1724  * To avoid having the function's ABI vary depending on the width of time_t,
1725  * we declare the argument as pg_time_t, which is cast-compatible with
1726  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1727  * This detail should be invisible to callers, at least at source code level.
1728  */
1731 {
1732  TimestampTz result;
1733 
1734  result = (TimestampTz) tm -
1736  result *= USECS_PER_SEC;
1737 
1738  return result;
1739 }
1740 
1741 /*
1742  * Convert a TimestampTz to time_t.
1743  *
1744  * This too is just marginally useful, but some places need it.
1745  *
1746  * To avoid having the function's ABI vary depending on the width of time_t,
1747  * we declare the result as pg_time_t, which is cast-compatible with
1748  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1749  * This detail should be invisible to callers, at least at source code level.
1750  */
1751 pg_time_t
1753 {
1754  pg_time_t result;
1755 
1756  result = (pg_time_t) (t / USECS_PER_SEC +
1758 
1759  return result;
1760 }
1761 
1762 /*
1763  * Produce a C-string representation of a TimestampTz.
1764  *
1765  * This is mostly for use in emitting messages. The primary difference
1766  * from timestamptz_out is that we force the output format to ISO. Note
1767  * also that the result is in a static buffer, not pstrdup'd.
1768  *
1769  * See also pg_strftime.
1770  */
1771 const char *
1773 {
1774  static char buf[MAXDATELEN + 1];
1775  int tz;
1776  struct pg_tm tt,
1777  *tm = &tt;
1778  fsec_t fsec;
1779  const char *tzn;
1780 
1781  if (TIMESTAMP_NOT_FINITE(t))
1782  EncodeSpecialTimestamp(t, buf);
1783  else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
1784  EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1785  else
1786  strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1787 
1788  return buf;
1789 }
1790 
1791 
1792 void
1793 dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
1794 {
1795  TimeOffset time;
1796 
1797  time = jd;
1798 
1799  *hour = time / USECS_PER_HOUR;
1800  time -= (*hour) * USECS_PER_HOUR;
1801  *min = time / USECS_PER_MINUTE;
1802  time -= (*min) * USECS_PER_MINUTE;
1803  *sec = time / USECS_PER_SEC;
1804  *fsec = time - (*sec * USECS_PER_SEC);
1805 } /* dt2time() */
1806 
1807 
1808 /*
1809  * timestamp2tm() - Convert timestamp data type to POSIX time structure.
1810  *
1811  * Note that year is _not_ 1900-based, but is an explicit full value.
1812  * Also, month is one-based, _not_ zero-based.
1813  * Returns:
1814  * 0 on success
1815  * -1 on out of range
1816  *
1817  * If attimezone is NULL, the global timezone setting will be used.
1818  */
1819 int
1820 timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
1821 {
1822  Timestamp date;
1823  Timestamp time;
1824  pg_time_t utime;
1825 
1826  /* Use session timezone if caller asks for default */
1827  if (attimezone == NULL)
1828  attimezone = session_timezone;
1829 
1830  time = dt;
1831  TMODULO(time, date, USECS_PER_DAY);
1832 
1833  if (time < INT64CONST(0))
1834  {
1835  time += USECS_PER_DAY;
1836  date -= 1;
1837  }
1838 
1839  /* add offset to go from J2000 back to standard Julian date */
1840  date += POSTGRES_EPOCH_JDATE;
1841 
1842  /* Julian day routine does not work for negative Julian days */
1843  if (date < 0 || date > (Timestamp) INT_MAX)
1844  return -1;
1845 
1846  j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1847  dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
1848 
1849  /* Done if no TZ conversion wanted */
1850  if (tzp == NULL)
1851  {
1852  tm->tm_isdst = -1;
1853  tm->tm_gmtoff = 0;
1854  tm->tm_zone = NULL;
1855  if (tzn != NULL)
1856  *tzn = NULL;
1857  return 0;
1858  }
1859 
1860  /*
1861  * If the time falls within the range of pg_time_t, use pg_localtime() to
1862  * rotate to the local time zone.
1863  *
1864  * First, convert to an integral timestamp, avoiding possibly
1865  * platform-specific roundoff-in-wrong-direction errors, and adjust to
1866  * Unix epoch. Then see if we can convert to pg_time_t without loss. This
1867  * coding avoids hardwiring any assumptions about the width of pg_time_t,
1868  * so it should behave sanely on machines without int64.
1869  */
1870  dt = (dt - *fsec) / USECS_PER_SEC +
1872  utime = (pg_time_t) dt;
1873  if ((Timestamp) utime == dt)
1874  {
1875  struct pg_tm *tx = pg_localtime(&utime, attimezone);
1876 
1877  tm->tm_year = tx->tm_year + 1900;
1878  tm->tm_mon = tx->tm_mon + 1;
1879  tm->tm_mday = tx->tm_mday;
1880  tm->tm_hour = tx->tm_hour;
1881  tm->tm_min = tx->tm_min;
1882  tm->tm_sec = tx->tm_sec;
1883  tm->tm_isdst = tx->tm_isdst;
1884  tm->tm_gmtoff = tx->tm_gmtoff;
1885  tm->tm_zone = tx->tm_zone;
1886  *tzp = -tm->tm_gmtoff;
1887  if (tzn != NULL)
1888  *tzn = tm->tm_zone;
1889  }
1890  else
1891  {
1892  /*
1893  * When out of range of pg_time_t, treat as GMT
1894  */
1895  *tzp = 0;
1896  /* Mark this as *no* time zone available */
1897  tm->tm_isdst = -1;
1898  tm->tm_gmtoff = 0;
1899  tm->tm_zone = NULL;
1900  if (tzn != NULL)
1901  *tzn = NULL;
1902  }
1903 
1904  return 0;
1905 }
1906 
1907 
1908 /* tm2timestamp()
1909  * Convert a tm structure to a timestamp data type.
1910  * Note that year is _not_ 1900-based, but is an explicit full value.
1911  * Also, month is one-based, _not_ zero-based.
1912  *
1913  * Returns -1 on failure (value out of range).
1914  */
1915 int
1916 tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
1917 {
1918  TimeOffset date;
1919  TimeOffset time;
1920 
1921  /* Prevent overflow in Julian-day routines */
1922  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1923  {
1924  *result = 0; /* keep compiler quiet */
1925  return -1;
1926  }
1927 
1928  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1929  time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
1930 
1931  *result = date * USECS_PER_DAY + time;
1932  /* check for major overflow */
1933  if ((*result - time) / USECS_PER_DAY != date)
1934  {
1935  *result = 0; /* keep compiler quiet */
1936  return -1;
1937  }
1938  /* check for just-barely overflow (okay except time-of-day wraps) */
1939  /* caution: we want to allow 1999-12-31 24:00:00 */
1940  if ((*result < 0 && date > 0) ||
1941  (*result > 0 && date < -1))
1942  {
1943  *result = 0; /* keep compiler quiet */
1944  return -1;
1945  }
1946  if (tzp != NULL)
1947  *result = dt2local(*result, -(*tzp));
1948 
1949  /* final range check catches just-out-of-range timestamps */
1950  if (!IS_VALID_TIMESTAMP(*result))
1951  {
1952  *result = 0; /* keep compiler quiet */
1953  return -1;
1954  }
1955 
1956  return 0;
1957 }
1958 
1959 
1960 /* interval2tm()
1961  * Convert an interval data type to a tm structure.
1962  */
1963 int
1964 interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
1965 {
1966  TimeOffset time;
1967  TimeOffset tfrac;
1968 
1969  tm->tm_year = span.month / MONTHS_PER_YEAR;
1970  tm->tm_mon = span.month % MONTHS_PER_YEAR;
1971  tm->tm_mday = span.day;
1972  time = span.time;
1973 
1974  tfrac = time / USECS_PER_HOUR;
1975  time -= tfrac * USECS_PER_HOUR;
1976  tm->tm_hour = tfrac;
1977  if (!SAMESIGN(tm->tm_hour, tfrac))
1978  ereport(ERROR,
1979  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1980  errmsg("interval out of range")));
1981  tfrac = time / USECS_PER_MINUTE;
1982  time -= tfrac * USECS_PER_MINUTE;
1983  tm->tm_min = tfrac;
1984  tfrac = time / USECS_PER_SEC;
1985  *fsec = time - (tfrac * USECS_PER_SEC);
1986  tm->tm_sec = tfrac;
1987 
1988  return 0;
1989 }
1990 
1991 int
1992 tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
1993 {
1994  double total_months = (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
1995 
1996  if (total_months > INT_MAX || total_months < INT_MIN)
1997  return -1;
1998  span->month = total_months;
1999  span->day = tm->tm_mday;
2000  span->time = (((((tm->tm_hour * INT64CONST(60)) +
2001  tm->tm_min) * INT64CONST(60)) +
2002  tm->tm_sec) * USECS_PER_SEC) + fsec;
2003 
2004  return 0;
2005 }
2006 
2007 static TimeOffset
2008 time2t(const int hour, const int min, const int sec, const fsec_t fsec)
2009 {
2010  return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
2011 }
2012 
2013 static Timestamp
2014 dt2local(Timestamp dt, int tz)
2015 {
2016  dt -= (tz * USECS_PER_SEC);
2017  return dt;
2018 }
2019 
2020 
2021 /*****************************************************************************
2022  * PUBLIC ROUTINES *
2023  *****************************************************************************/
2024 
2025 
2026 Datum
2028 {
2030 
2031  PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
2032 }
2033 
2034 Datum
2036 {
2037  PG_RETURN_BOOL(true);
2038 }
2039 
2040 
2041 /*----------------------------------------------------------
2042  * Relational operators for timestamp.
2043  *---------------------------------------------------------*/
2044 
2045 void
2047 {
2048  struct pg_tm *t0;
2049  pg_time_t epoch = 0;
2050 
2051  t0 = pg_gmtime(&epoch);
2052 
2053  if (t0 == NULL)
2054  elog(ERROR, "could not convert epoch to timestamp: %m");
2055 
2056  tm->tm_year = t0->tm_year;
2057  tm->tm_mon = t0->tm_mon;
2058  tm->tm_mday = t0->tm_mday;
2059  tm->tm_hour = t0->tm_hour;
2060  tm->tm_min = t0->tm_min;
2061  tm->tm_sec = t0->tm_sec;
2062 
2063  tm->tm_year += 1900;
2064  tm->tm_mon++;
2065 }
2066 
2067 Timestamp
2069 {
2070  Timestamp dt;
2071  struct pg_tm tt,
2072  *tm = &tt;
2073 
2074  GetEpochTime(tm);
2075  /* we don't bother to test for failure ... */
2076  tm2timestamp(tm, 0, NULL, &dt);
2077 
2078  return dt;
2079 } /* SetEpochTimestamp() */
2080 
2081 /*
2082  * We are currently sharing some code between timestamp and timestamptz.
2083  * The comparison functions are among them. - thomas 2001-09-25
2084  *
2085  * timestamp_relop - is timestamp1 relop timestamp2
2086  */
2087 int
2089 {
2090  return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2091 }
2092 
2093 Datum
2095 {
2096  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2097  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2098 
2099  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
2100 }
2101 
2102 Datum
2104 {
2105  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2106  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2107 
2108  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2109 }
2110 
2111 Datum
2113 {
2114  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2115  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2116 
2117  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2118 }
2119 
2120 Datum
2122 {
2123  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2124  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2125 
2126  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2127 }
2128 
2129 Datum
2131 {
2132  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2133  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2134 
2135  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2136 }
2137 
2138 Datum
2140 {
2141  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2142  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2143 
2144  PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2145 }
2146 
2147 Datum
2149 {
2150  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2151  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2152 
2154 }
2155 
2156 /* note: this is used for timestamptz also */
2157 static int
2159 {
2162 
2163  return timestamp_cmp_internal(a, b);
2164 }
2165 
2166 Datum
2168 {
2170 
2171  ssup->comparator = timestamp_fastcmp;
2172  PG_RETURN_VOID();
2173 }
2174 
2175 Datum
2177 {
2178  return hashint8(fcinfo);
2179 }
2180 
2181 Datum
2183 {
2184  return hashint8extended(fcinfo);
2185 }
2186 
2187 /*
2188  * Cross-type comparison functions for timestamp vs timestamptz
2189  */
2190 
2191 int32
2193 {
2194  TimestampTz dt1;
2195  int overflow;
2196 
2197  dt1 = timestamp2timestamptz_opt_overflow(timestampVal, &overflow);
2198  if (overflow > 0)
2199  {
2200  /* dt1 is larger than any finite timestamp, but less than infinity */
2201  return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
2202  }
2203  if (overflow < 0)
2204  {
2205  /* dt1 is less than any finite timestamp, but more than -infinity */
2206  return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
2207  }
2208 
2209  return timestamptz_cmp_internal(dt1, dt2);
2210 }
2211 
2212 Datum
2214 {
2215  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2217 
2218  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) == 0);
2219 }
2220 
2221 Datum
2223 {
2224  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2226 
2227  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) != 0);
2228 }
2229 
2230 Datum
2232 {
2233  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2235 
2236  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) < 0);
2237 }
2238 
2239 Datum
2241 {
2242  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2244 
2245  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) > 0);
2246 }
2247 
2248 Datum
2250 {
2251  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2253 
2254  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) <= 0);
2255 }
2256 
2257 Datum
2259 {
2260  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2262 
2263  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) >= 0);
2264 }
2265 
2266 Datum
2268 {
2269  Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2271 
2273 }
2274 
2275 Datum
2277 {
2279  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2280 
2281  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) == 0);
2282 }
2283 
2284 Datum
2286 {
2288  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2289 
2290  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) != 0);
2291 }
2292 
2293 Datum
2295 {
2297  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2298 
2299  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) > 0);
2300 }
2301 
2302 Datum
2304 {
2306  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2307 
2308  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) < 0);
2309 }
2310 
2311 Datum
2313 {
2315  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2316 
2317  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) >= 0);
2318 }
2319 
2320 Datum
2322 {
2324  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2325 
2326  PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) <= 0);
2327 }
2328 
2329 Datum
2331 {
2333  Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2334 
2336 }
2337 
2338 
2339 /*
2340  * interval_relop - is interval1 relop interval2
2341  *
2342  * Interval comparison is based on converting interval values to a linear
2343  * representation expressed in the units of the time field (microseconds,
2344  * in the case of integer timestamps) with days assumed to be always 24 hours
2345  * and months assumed to be always 30 days. To avoid overflow, we need a
2346  * wider-than-int64 datatype for the linear representation, so use INT128.
2347  */
2348 
2349 static inline INT128
2351 {
2352  INT128 span;
2353  int64 dayfraction;
2354  int64 days;
2355 
2356  /*
2357  * Separate time field into days and dayfraction, then add the month and
2358  * day fields to the days part. We cannot overflow int64 days here.
2359  */
2360  dayfraction = interval->time % USECS_PER_DAY;
2361  days = interval->time / USECS_PER_DAY;
2362  days += interval->month * INT64CONST(30);
2363  days += interval->day;
2364 
2365  /* Widen dayfraction to 128 bits */
2366  span = int64_to_int128(dayfraction);
2367 
2368  /* Scale up days to microseconds, forming a 128-bit product */
2370 
2371  return span;
2372 }
2373 
2374 static int
2375 interval_cmp_internal(Interval *interval1, Interval *interval2)
2376 {
2377  INT128 span1 = interval_cmp_value(interval1);
2378  INT128 span2 = interval_cmp_value(interval2);
2379 
2380  return int128_compare(span1, span2);
2381 }
2382 
2383 Datum
2385 {
2386  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2387  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2388 
2389  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
2390 }
2391 
2392 Datum
2394 {
2395  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2396  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2397 
2398  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
2399 }
2400 
2401 Datum
2403 {
2404  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2405  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2406 
2407  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
2408 }
2409 
2410 Datum
2412 {
2413  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2414  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2415 
2416  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
2417 }
2418 
2419 Datum
2421 {
2422  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2423  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2424 
2425  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
2426 }
2427 
2428 Datum
2430 {
2431  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2432  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2433 
2434  PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
2435 }
2436 
2437 Datum
2439 {
2440  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2441  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2442 
2443  PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
2444 }
2445 
2446 /*
2447  * Hashing for intervals
2448  *
2449  * We must produce equal hashvals for values that interval_cmp_internal()
2450  * considers equal. So, compute the net span the same way it does,
2451  * and then hash that.
2452  */
2453 Datum
2455 {
2457  INT128 span = interval_cmp_value(interval);
2458  int64 span64;
2459 
2460  /*
2461  * Use only the least significant 64 bits for hashing. The upper 64 bits
2462  * seldom add any useful information, and besides we must do it like this
2463  * for compatibility with hashes calculated before use of INT128 was
2464  * introduced.
2465  */
2466  span64 = int128_to_int64(span);
2467 
2469 }
2470 
2471 Datum
2473 {
2475  INT128 span = interval_cmp_value(interval);
2476  int64 span64;
2477 
2478  /* Same approach as interval_hash */
2479  span64 = int128_to_int64(span);
2480 
2482  PG_GETARG_DATUM(1));
2483 }
2484 
2485 /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
2486  *
2487  * Algorithm is per SQL spec. This is much harder than you'd think
2488  * because the spec requires us to deliver a non-null answer in some cases
2489  * where some of the inputs are null.
2490  */
2491 Datum
2493 {
2494  /*
2495  * The arguments are Timestamps, but we leave them as generic Datums to
2496  * avoid unnecessary conversions between value and reference forms --- not
2497  * to mention possible dereferences of null pointers.
2498  */
2499  Datum ts1 = PG_GETARG_DATUM(0);
2500  Datum te1 = PG_GETARG_DATUM(1);
2501  Datum ts2 = PG_GETARG_DATUM(2);
2502  Datum te2 = PG_GETARG_DATUM(3);
2503  bool ts1IsNull = PG_ARGISNULL(0);
2504  bool te1IsNull = PG_ARGISNULL(1);
2505  bool ts2IsNull = PG_ARGISNULL(2);
2506  bool te2IsNull = PG_ARGISNULL(3);
2507 
2508 #define TIMESTAMP_GT(t1,t2) \
2509  DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
2510 #define TIMESTAMP_LT(t1,t2) \
2511  DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
2512 
2513  /*
2514  * If both endpoints of interval 1 are null, the result is null (unknown).
2515  * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2516  * take ts1 as the lesser endpoint.
2517  */
2518  if (ts1IsNull)
2519  {
2520  if (te1IsNull)
2521  PG_RETURN_NULL();
2522  /* swap null for non-null */
2523  ts1 = te1;
2524  te1IsNull = true;
2525  }
2526  else if (!te1IsNull)
2527  {
2528  if (TIMESTAMP_GT(ts1, te1))
2529  {
2530  Datum tt = ts1;
2531 
2532  ts1 = te1;
2533  te1 = tt;
2534  }
2535  }
2536 
2537  /* Likewise for interval 2. */
2538  if (ts2IsNull)
2539  {
2540  if (te2IsNull)
2541  PG_RETURN_NULL();
2542  /* swap null for non-null */
2543  ts2 = te2;
2544  te2IsNull = true;
2545  }
2546  else if (!te2IsNull)
2547  {
2548  if (TIMESTAMP_GT(ts2, te2))
2549  {
2550  Datum tt = ts2;
2551 
2552  ts2 = te2;
2553  te2 = tt;
2554  }
2555  }
2556 
2557  /*
2558  * At this point neither ts1 nor ts2 is null, so we can consider three
2559  * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2560  */
2561  if (TIMESTAMP_GT(ts1, ts2))
2562  {
2563  /*
2564  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2565  * in the presence of nulls it's not quite completely so.
2566  */
2567  if (te2IsNull)
2568  PG_RETURN_NULL();
2569  if (TIMESTAMP_LT(ts1, te2))
2570  PG_RETURN_BOOL(true);
2571  if (te1IsNull)
2572  PG_RETURN_NULL();
2573 
2574  /*
2575  * If te1 is not null then we had ts1 <= te1 above, and we just found
2576  * ts1 >= te2, hence te1 >= te2.
2577  */
2578  PG_RETURN_BOOL(false);
2579  }
2580  else if (TIMESTAMP_LT(ts1, ts2))
2581  {
2582  /* This case is ts2 < te1 OR te2 < te1 */
2583  if (te1IsNull)
2584  PG_RETURN_NULL();
2585  if (TIMESTAMP_LT(ts2, te1))
2586  PG_RETURN_BOOL(true);
2587  if (te2IsNull)
2588  PG_RETURN_NULL();
2589 
2590  /*
2591  * If te2 is not null then we had ts2 <= te2 above, and we just found
2592  * ts2 >= te1, hence te2 >= te1.
2593  */
2594  PG_RETURN_BOOL(false);
2595  }
2596  else
2597  {
2598  /*
2599  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2600  * rather silly way of saying "true if both are non-null, else null".
2601  */
2602  if (te1IsNull || te2IsNull)
2603  PG_RETURN_NULL();
2604  PG_RETURN_BOOL(true);
2605  }
2606 
2607 #undef TIMESTAMP_GT
2608 #undef TIMESTAMP_LT
2609 }
2610 
2611 
2612 /*----------------------------------------------------------
2613  * "Arithmetic" operators on date/times.
2614  *---------------------------------------------------------*/
2615 
2616 Datum
2618 {
2619  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2620  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2621  Timestamp result;
2622 
2623  /* use timestamp_cmp_internal to be sure this agrees with comparisons */
2624  if (timestamp_cmp_internal(dt1, dt2) < 0)
2625  result = dt1;
2626  else
2627  result = dt2;
2628  PG_RETURN_TIMESTAMP(result);
2629 }
2630 
2631 Datum
2633 {
2634  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2635  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2636  Timestamp result;
2637 
2638  if (timestamp_cmp_internal(dt1, dt2) > 0)
2639  result = dt1;
2640  else
2641  result = dt2;
2642  PG_RETURN_TIMESTAMP(result);
2643 }
2644 
2645 
2646 Datum
2648 {
2649  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2650  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2651  Interval *result;
2652 
2653  result = (Interval *) palloc(sizeof(Interval));
2654 
2655  if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
2656  ereport(ERROR,
2657  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2658  errmsg("cannot subtract infinite timestamps")));
2659 
2660  result->time = dt1 - dt2;
2661 
2662  result->month = 0;
2663  result->day = 0;
2664 
2665  /*----------
2666  * This is wrong, but removing it breaks a lot of regression tests.
2667  * For example:
2668  *
2669  * test=> SET timezone = 'EST5EDT';
2670  * test=> SELECT
2671  * test-> ('2005-10-30 13:22:00-05'::timestamptz -
2672  * test(> '2005-10-29 13:22:00-04'::timestamptz);
2673  * ?column?
2674  * ----------------
2675  * 1 day 01:00:00
2676  * (1 row)
2677  *
2678  * so adding that to the first timestamp gets:
2679  *
2680  * test=> SELECT
2681  * test-> ('2005-10-29 13:22:00-04'::timestamptz +
2682  * test(> ('2005-10-30 13:22:00-05'::timestamptz -
2683  * test(> '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
2684  * timezone
2685  * --------------------
2686  * 2005-10-30 14:22:00
2687  * (1 row)
2688  *----------
2689  */
2691  IntervalPGetDatum(result)));
2692 
2693  PG_RETURN_INTERVAL_P(result);
2694 }
2695 
2696 /*
2697  * interval_justify_interval()
2698  *
2699  * Adjust interval so 'month', 'day', and 'time' portions are within
2700  * customary bounds. Specifically:
2701  *
2702  * 0 <= abs(time) < 24 hours
2703  * 0 <= abs(day) < 30 days
2704  *
2705  * Also, the sign bit on all three fields is made equal, so either
2706  * all three fields are negative or all are positive.
2707  */
2708 Datum
2710 {
2711  Interval *span = PG_GETARG_INTERVAL_P(0);
2712  Interval *result;
2713  TimeOffset wholeday;
2714  int32 wholemonth;
2715 
2716  result = (Interval *) palloc(sizeof(Interval));
2717  result->month = span->month;
2718  result->day = span->day;
2719  result->time = span->time;
2720 
2721  TMODULO(result->time, wholeday, USECS_PER_DAY);
2722  result->day += wholeday; /* could overflow... */
2723 
2724  wholemonth = result->day / DAYS_PER_MONTH;
2725  result->day -= wholemonth * DAYS_PER_MONTH;
2726  result->month += wholemonth;
2727 
2728  if (result->month > 0 &&
2729  (result->day < 0 || (result->day == 0 && result->time < 0)))
2730  {
2731  result->day += DAYS_PER_MONTH;
2732  result->month--;
2733  }
2734  else if (result->month < 0 &&
2735  (result->day > 0 || (result->day == 0 && result->time > 0)))
2736  {
2737  result->day -= DAYS_PER_MONTH;
2738  result->month++;
2739  }
2740 
2741  if (result->day > 0 && result->time < 0)
2742  {
2743  result->time += USECS_PER_DAY;
2744  result->day--;
2745  }
2746  else if (result->day < 0 && result->time > 0)
2747  {
2748  result->time -= USECS_PER_DAY;
2749  result->day++;
2750  }
2751 
2752  PG_RETURN_INTERVAL_P(result);
2753 }
2754 
2755 /*
2756  * interval_justify_hours()
2757  *
2758  * Adjust interval so 'time' contains less than a whole day, adding
2759  * the excess to 'day'. This is useful for
2760  * situations (such as non-TZ) where '1 day' = '24 hours' is valid,
2761  * e.g. interval subtraction and division.
2762  */
2763 Datum
2765 {
2766  Interval *span = PG_GETARG_INTERVAL_P(0);
2767  Interval *result;
2768  TimeOffset wholeday;
2769 
2770  result = (Interval *) palloc(sizeof(Interval));
2771  result->month = span->month;
2772  result->day = span->day;
2773  result->time = span->time;
2774 
2775  TMODULO(result->time, wholeday, USECS_PER_DAY);
2776  result->day += wholeday; /* could overflow... */
2777 
2778  if (result->day > 0 && result->time < 0)
2779  {
2780  result->time += USECS_PER_DAY;
2781  result->day--;
2782  }
2783  else if (result->day < 0 && result->time > 0)
2784  {
2785  result->time -= USECS_PER_DAY;
2786  result->day++;
2787  }
2788 
2789  PG_RETURN_INTERVAL_P(result);
2790 }
2791 
2792 /*
2793  * interval_justify_days()
2794  *
2795  * Adjust interval so 'day' contains less than 30 days, adding
2796  * the excess to 'month'.
2797  */
2798 Datum
2800 {
2801  Interval *span = PG_GETARG_INTERVAL_P(0);
2802  Interval *result;
2803  int32 wholemonth;
2804 
2805  result = (Interval *) palloc(sizeof(Interval));
2806  result->month = span->month;
2807  result->day = span->day;
2808  result->time = span->time;
2809 
2810  wholemonth = result->day / DAYS_PER_MONTH;
2811  result->day -= wholemonth * DAYS_PER_MONTH;
2812  result->month += wholemonth;
2813 
2814  if (result->month > 0 && result->day < 0)
2815  {
2816  result->day += DAYS_PER_MONTH;
2817  result->month--;
2818  }
2819  else if (result->month < 0 && result->day > 0)
2820  {
2821  result->day -= DAYS_PER_MONTH;
2822  result->month++;
2823  }
2824 
2825  PG_RETURN_INTERVAL_P(result);
2826 }
2827 
2828 /* timestamp_pl_interval()
2829  * Add an interval to a timestamp data type.
2830  * Note that interval has provisions for qualitative year/month and day
2831  * units, so try to do the right thing with them.
2832  * To add a month, increment the month, and use the same day of month.
2833  * Then, if the next month has fewer days, set the day of month
2834  * to the last day of month.
2835  * To add a day, increment the mday, and use the same time of day.
2836  * Lastly, add in the "quantitative time".
2837  */
2838 Datum
2840 {
2842  Interval *span = PG_GETARG_INTERVAL_P(1);
2843  Timestamp result;
2844 
2845  if (TIMESTAMP_NOT_FINITE(timestamp))
2846  result = timestamp;
2847  else
2848  {
2849  if (span->month != 0)
2850  {
2851  struct pg_tm tt,
2852  *tm = &tt;
2853  fsec_t fsec;
2854 
2855  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
2856  ereport(ERROR,
2857  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2858  errmsg("timestamp out of range")));
2859 
2860  tm->tm_mon += span->month;
2861  if (tm->tm_mon > MONTHS_PER_YEAR)
2862  {
2863  tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
2864  tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
2865  }
2866  else if (tm->tm_mon < 1)
2867  {
2868  tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
2870  }
2871 
2872  /* adjust for end of month boundary problems... */
2873  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2874  tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
2875 
2876  if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
2877  ereport(ERROR,
2878  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2879  errmsg("timestamp out of range")));
2880  }
2881 
2882  if (span->day != 0)
2883  {
2884  struct pg_tm tt,
2885  *tm = &tt;
2886  fsec_t fsec;
2887  int julian;
2888 
2889  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
2890  ereport(ERROR,
2891  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2892  errmsg("timestamp out of range")));
2893 
2894  /* Add days by converting to and from Julian */
2895  julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
2896  j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2897 
2898  if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
2899  ereport(ERROR,
2900  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2901  errmsg("timestamp out of range")));
2902  }
2903 
2904  timestamp += span->time;
2905 
2906  if (!IS_VALID_TIMESTAMP(timestamp))
2907  ereport(ERROR,
2908  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2909  errmsg("timestamp out of range")));
2910 
2911  result = timestamp;
2912  }
2913 
2914  PG_RETURN_TIMESTAMP(result);
2915 }
2916 
2917 Datum
2919 {
2921  Interval *span = PG_GETARG_INTERVAL_P(1);
2922  Interval tspan;
2923 
2924  tspan.month = -span->month;
2925  tspan.day = -span->day;
2926  tspan.time = -span->time;
2927 
2929  TimestampGetDatum(timestamp),
2930  PointerGetDatum(&tspan));
2931 }
2932 
2933 
2934 /* timestamptz_pl_interval()
2935  * Add an interval to a timestamp with time zone data type.
2936  * Note that interval has provisions for qualitative year/month
2937  * units, so try to do the right thing with them.
2938  * To add a month, increment the month, and use the same day of month.
2939  * Then, if the next month has fewer days, set the day of month
2940  * to the last day of month.
2941  * Lastly, add in the "quantitative time".
2942  */
2943 Datum
2945 {
2947  Interval *span = PG_GETARG_INTERVAL_P(1);
2948  TimestampTz result;
2949  int tz;
2950 
2951  if (TIMESTAMP_NOT_FINITE(timestamp))
2952  result = timestamp;
2953  else
2954  {
2955  if (span->month != 0)
2956  {
2957  struct pg_tm tt,
2958  *tm = &tt;
2959  fsec_t fsec;
2960 
2961  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2962  ereport(ERROR,
2963  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2964  errmsg("timestamp out of range")));
2965 
2966  tm->tm_mon += span->month;
2967  if (tm->tm_mon > MONTHS_PER_YEAR)
2968  {
2969  tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
2970  tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
2971  }
2972  else if (tm->tm_mon < 1)
2973  {
2974  tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
2976  }
2977 
2978  /* adjust for end of month boundary problems... */
2979  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2980  tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
2981 
2983 
2984  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
2985  ereport(ERROR,
2986  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2987  errmsg("timestamp out of range")));
2988  }
2989 
2990  if (span->day != 0)
2991  {
2992  struct pg_tm tt,
2993  *tm = &tt;
2994  fsec_t fsec;
2995  int julian;
2996 
2997  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2998  ereport(ERROR,
2999  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3000  errmsg("timestamp out of range")));
3001 
3002  /* Add days by converting to and from Julian */
3003  julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
3004  j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3005 
3007 
3008  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
3009  ereport(ERROR,
3010  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3011  errmsg("timestamp out of range")));
3012  }
3013 
3014  timestamp += span->time;
3015 
3016  if (!IS_VALID_TIMESTAMP(timestamp))
3017  ereport(ERROR,
3018  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3019  errmsg("timestamp out of range")));
3020 
3021  result = timestamp;
3022  }
3023 
3024  PG_RETURN_TIMESTAMP(result);
3025 }
3026 
3027 Datum
3029 {
3031  Interval *span = PG_GETARG_INTERVAL_P(1);
3032  Interval tspan;
3033 
3034  tspan.month = -span->month;
3035  tspan.day = -span->day;
3036  tspan.time = -span->time;
3037 
3039  TimestampGetDatum(timestamp),
3040  PointerGetDatum(&tspan));
3041 }
3042 
3043 
3044 Datum
3046 {
3048  Interval *result;
3049 
3050  result = (Interval *) palloc(sizeof(Interval));
3051 
3052  result->time = -interval->time;
3053  /* overflow check copied from int4um */
3054  if (interval->time != 0 && SAMESIGN(result->time, interval->time))
3055  ereport(ERROR,
3056  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3057  errmsg("interval out of range")));
3058  result->day = -interval->day;
3059  if (interval->day != 0 && SAMESIGN(result->day, interval->day))
3060  ereport(ERROR,
3061  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3062  errmsg("interval out of range")));
3063  result->month = -interval->month;
3064  if (interval->month != 0 && SAMESIGN(result->month, interval->month))
3065  ereport(ERROR,
3066  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3067  errmsg("interval out of range")));
3068 
3069  PG_RETURN_INTERVAL_P(result);
3070 }
3071 
3072 
3073 Datum
3075 {
3076  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3077  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3078  Interval *result;
3079 
3080  /* use interval_cmp_internal to be sure this agrees with comparisons */
3081  if (interval_cmp_internal(interval1, interval2) < 0)
3082  result = interval1;
3083  else
3084  result = interval2;
3085  PG_RETURN_INTERVAL_P(result);
3086 }
3087 
3088 Datum
3090 {
3091  Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3092  Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3093  Interval *result;
3094 
3095  if (interval_cmp_internal(interval1, interval2) > 0)
3096  result = interval1;
3097  else
3098  result = interval2;
3099  PG_RETURN_INTERVAL_P(result);
3100 }
3101 
3102 Datum
3104 {
3105  Interval *span1 = PG_GETARG_INTERVAL_P(0);
3106  Interval *span2 = PG_GETARG_INTERVAL_P(1);
3107  Interval *result;
3108 
3109  result = (Interval *) palloc(sizeof(Interval));
3110 
3111  result->month = span1->month + span2->month;
3112  /* overflow check copied from int4pl */
3113  if (SAMESIGN(span1->month, span2->month) &&
3114  !SAMESIGN(result->month, span1->month))
3115  ereport(ERROR,
3116  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3117  errmsg("interval out of range")));
3118 
3119  result->day = span1->day + span2->day;
3120  if (SAMESIGN(span1->day, span2->day) &&
3121  !SAMESIGN(result->day, span1->day))
3122  ereport(ERROR,
3123  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3124  errmsg("interval out of range")));
3125 
3126  result->time = span1->time + span2->time;
3127  if (SAMESIGN(span1->time, span2->time) &&
3128  !SAMESIGN(result->time, span1->time))
3129  ereport(ERROR,
3130  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3131  errmsg("interval out of range")));
3132 
3133  PG_RETURN_INTERVAL_P(result);
3134 }
3135 
3136 Datum
3138 {
3139  Interval *span1 = PG_GETARG_INTERVAL_P(0);
3140  Interval *span2 = PG_GETARG_INTERVAL_P(1);
3141  Interval *result;
3142 
3143  result = (Interval *) palloc(sizeof(Interval));
3144 
3145  result->month = span1->month - span2->month;
3146  /* overflow check copied from int4mi */
3147  if (!SAMESIGN(span1->month, span2->month) &&
3148  !SAMESIGN(result->month, span1->month))
3149  ereport(ERROR,
3150  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3151  errmsg("interval out of range")));
3152 
3153  result->day = span1->day - span2->day;
3154  if (!SAMESIGN(span1->day, span2->day) &&
3155  !SAMESIGN(result->day, span1->day))
3156  ereport(ERROR,
3157  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3158  errmsg("interval out of range")));
3159 
3160  result->time = span1->time - span2->time;
3161  if (!SAMESIGN(span1->time, span2->time) &&
3162  !SAMESIGN(result->time, span1->time))
3163  ereport(ERROR,
3164  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3165  errmsg("interval out of range")));
3166 
3167  PG_RETURN_INTERVAL_P(result);
3168 }
3169 
3170 /*
3171  * There is no interval_abs(): it is unclear what value to return:
3172  * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3173  * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3174  */
3175 
3176 Datum
3178 {
3179  Interval *span = PG_GETARG_INTERVAL_P(0);
3180  float8 factor = PG_GETARG_FLOAT8(1);
3181  double month_remainder_days,
3182  sec_remainder,
3183  result_double;
3184  int32 orig_month = span->month,
3185  orig_day = span->day;
3186  Interval *result;
3187 
3188  result = (Interval *) palloc(sizeof(Interval));
3189 
3190  result_double = span->month * factor;
3191  if (isnan(result_double) ||
3192  result_double > INT_MAX || result_double < INT_MIN)
3193  ereport(ERROR,
3194  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3195  errmsg("interval out of range")));
3196  result->month = (int32) result_double;
3197 
3198  result_double = span->day * factor;
3199  if (isnan(result_double) ||
3200  result_double > INT_MAX || result_double < INT_MIN)
3201  ereport(ERROR,
3202  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3203  errmsg("interval out of range")));
3204  result->day = (int32) result_double;
3205 
3206  /*
3207  * The above correctly handles the whole-number part of the month and day
3208  * products, but we have to do something with any fractional part
3209  * resulting when the factor is non-integral. We cascade the fractions
3210  * down to lower units using the conversion factors DAYS_PER_MONTH and
3211  * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
3212  * so by the representation. The user can choose to cascade up later,
3213  * using justify_hours and/or justify_days.
3214  */
3215 
3216  /*
3217  * Fractional months full days into days.
3218  *
3219  * Floating point calculation are inherently imprecise, so these
3220  * calculations are crafted to produce the most reliable result possible.
3221  * TSROUND() is needed to more accurately produce whole numbers where
3222  * appropriate.
3223  */
3224  month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
3225  month_remainder_days = TSROUND(month_remainder_days);
3226  sec_remainder = (orig_day * factor - result->day +
3227  month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3228  sec_remainder = TSROUND(sec_remainder);
3229 
3230  /*
3231  * Might have 24:00:00 hours due to rounding, or >24 hours because of time
3232  * cascade from months and days. It might still be >24 if the combination
3233  * of cascade and the seconds factor operation itself.
3234  */
3235  if (Abs(sec_remainder) >= SECS_PER_DAY)
3236  {
3237  result->day += (int) (sec_remainder / SECS_PER_DAY);
3238  sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3239  }
3240 
3241  /* cascade units down */
3242  result->day += (int32) month_remainder_days;
3243  result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
3244  if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3245  ereport(ERROR,
3246  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3247  errmsg("interval out of range")));
3248  result->time = (int64) result_double;
3249 
3250  PG_RETURN_INTERVAL_P(result);
3251 }
3252 
3253 Datum
3255 {
3256  /* Args are float8 and Interval *, but leave them as generic Datum */
3257  Datum factor = PG_GETARG_DATUM(0);
3258  Datum span = PG_GETARG_DATUM(1);
3259 
3260  return DirectFunctionCall2(interval_mul, span, factor);
3261 }
3262 
3263 Datum
3265 {
3266  Interval *span = PG_GETARG_INTERVAL_P(0);
3267  float8 factor = PG_GETARG_FLOAT8(1);
3268  double month_remainder_days,
3269  sec_remainder;
3270  int32 orig_month = span->month,
3271  orig_day = span->day;
3272  Interval *result;
3273 
3274  result = (Interval *) palloc(sizeof(Interval));
3275 
3276  if (factor == 0.0)
3277  ereport(ERROR,
3278  (errcode(ERRCODE_DIVISION_BY_ZERO),
3279  errmsg("division by zero")));
3280 
3281  result->month = (int32) (span->month / factor);
3282  result->day = (int32) (span->day / factor);
3283 
3284  /*
3285  * Fractional months full days into days. See comment in interval_mul().
3286  */
3287  month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
3288  month_remainder_days = TSROUND(month_remainder_days);
3289  sec_remainder = (orig_day / factor - result->day +
3290  month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3291  sec_remainder = TSROUND(sec_remainder);
3292  if (Abs(sec_remainder) >= SECS_PER_DAY)
3293  {
3294  result->day += (int) (sec_remainder / SECS_PER_DAY);
3295  sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3296  }
3297 
3298  /* cascade units down */
3299  result->day += (int32) month_remainder_days;
3300  result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
3301 
3302  PG_RETURN_INTERVAL_P(result);
3303 }
3304 
3305 
3306 /*
3307  * in_range support functions for timestamps and intervals.
3308  *
3309  * Per SQL spec, we support these with interval as the offset type.
3310  * The spec's restriction that the offset not be negative is a bit hard to
3311  * decipher for intervals, but we choose to interpret it the same as our
3312  * interval comparison operators would.
3313  */
3314 
3315 Datum
3317 {
3320  Interval *offset = PG_GETARG_INTERVAL_P(2);
3321  bool sub = PG_GETARG_BOOL(3);
3322  bool less = PG_GETARG_BOOL(4);
3323  TimestampTz sum;
3324 
3325  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3326  ereport(ERROR,
3327  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3328  errmsg("invalid preceding or following size in window function")));
3329 
3330  /* We don't currently bother to avoid overflow hazards here */
3331  if (sub)
3333  TimestampTzGetDatum(base),
3334  IntervalPGetDatum(offset)));
3335  else
3337  TimestampTzGetDatum(base),
3338  IntervalPGetDatum(offset)));
3339 
3340  if (less)
3341  PG_RETURN_BOOL(val <= sum);
3342  else
3343  PG_RETURN_BOOL(val >= sum);
3344 }
3345 
3346 Datum
3348 {
3350  Timestamp base = PG_GETARG_TIMESTAMP(1);
3351  Interval *offset = PG_GETARG_INTERVAL_P(2);
3352  bool sub = PG_GETARG_BOOL(3);
3353  bool less = PG_GETARG_BOOL(4);
3354  Timestamp sum;
3355 
3356  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3357  ereport(ERROR,
3358  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3359  errmsg("invalid preceding or following size in window function")));
3360 
3361  /* We don't currently bother to avoid overflow hazards here */
3362  if (sub)
3364  TimestampGetDatum(base),
3365  IntervalPGetDatum(offset)));
3366  else
3368  TimestampGetDatum(base),
3369  IntervalPGetDatum(offset)));
3370 
3371  if (less)
3372  PG_RETURN_BOOL(val <= sum);
3373  else
3374  PG_RETURN_BOOL(val >= sum);
3375 }
3376 
3377 Datum
3379 {
3381  Interval *base = PG_GETARG_INTERVAL_P(1);
3382  Interval *offset = PG_GETARG_INTERVAL_P(2);
3383  bool sub = PG_GETARG_BOOL(3);
3384  bool less = PG_GETARG_BOOL(4);
3385  Interval *sum;
3386 
3387  if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3388  ereport(ERROR,
3389  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3390  errmsg("invalid preceding or following size in window function")));
3391 
3392  /* We don't currently bother to avoid overflow hazards here */
3393  if (sub)
3395  IntervalPGetDatum(base),
3396  IntervalPGetDatum(offset)));
3397  else
3399  IntervalPGetDatum(base),
3400  IntervalPGetDatum(offset)));
3401 
3402  if (less)
3403  PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3404  else
3405  PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3406 }
3407 
3408 
3409 /*
3410  * interval_accum, interval_accum_inv, and interval_avg implement the
3411  * AVG(interval) aggregate.
3412  *
3413  * The transition datatype for this aggregate is a 2-element array of
3414  * intervals, where the first is the running sum and the second contains
3415  * the number of values so far in its 'time' field. This is a bit ugly
3416  * but it beats inventing a specialized datatype for the purpose.
3417  */
3418 
3419 Datum
3421 {
3422  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3424  Datum *transdatums;
3425  int ndatums;
3426  Interval sumX,
3427  N;
3428  Interval *newsum;
3429  ArrayType *result;
3430 
3431  deconstruct_array(transarray,
3432  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3433  &transdatums, NULL, &ndatums);
3434  if (ndatums != 2)
3435  elog(ERROR, "expected 2-element interval array");
3436 
3437  sumX = *(DatumGetIntervalP(transdatums[0]));
3438  N = *(DatumGetIntervalP(transdatums[1]));
3439 
3441  IntervalPGetDatum(&sumX),
3442  IntervalPGetDatum(newval)));
3443  N.time += 1;
3444 
3445  transdatums[0] = IntervalPGetDatum(newsum);
3446  transdatums[1] = IntervalPGetDatum(&N);
3447 
3448  result = construct_array(transdatums, 2,
3449  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE);
3450 
3451  PG_RETURN_ARRAYTYPE_P(result);
3452 }
3453 
3454 Datum
3456 {
3457  ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
3458  ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
3459  Datum *transdatums1;
3460  Datum *transdatums2;
3461  int ndatums1;
3462  int ndatums2;
3463  Interval sum1,
3464  N1;
3465  Interval sum2,
3466  N2;
3467 
3468  Interval *newsum;
3469  ArrayType *result;
3470 
3471  deconstruct_array(transarray1,
3472  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3473  &transdatums1, NULL, &ndatums1);
3474  if (ndatums1 != 2)
3475  elog(ERROR, "expected 2-element interval array");
3476 
3477  sum1 = *(DatumGetIntervalP(transdatums1[0]));
3478  N1 = *(DatumGetIntervalP(transdatums1[1]));
3479 
3480  deconstruct_array(transarray2,
3481  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3482  &transdatums2, NULL, &ndatums2);
3483  if (ndatums2 != 2)
3484  elog(ERROR, "expected 2-element interval array");
3485 
3486  sum2 = *(DatumGetIntervalP(transdatums2[0]));
3487  N2 = *(DatumGetIntervalP(transdatums2[1]));
3488 
3490  IntervalPGetDatum(&sum1),
3491  IntervalPGetDatum(&sum2)));
3492  N1.time += N2.time;
3493 
3494  transdatums1[0] = IntervalPGetDatum(newsum);
3495  transdatums1[1] = IntervalPGetDatum(&N1);
3496 
3497  result = construct_array(transdatums1, 2,
3498  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE);
3499 
3500  PG_RETURN_ARRAYTYPE_P(result);
3501 }
3502 
3503 Datum
3505 {
3506  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3508  Datum *transdatums;
3509  int ndatums;
3510  Interval sumX,
3511  N;
3512  Interval *newsum;
3513  ArrayType *result;
3514 
3515  deconstruct_array(transarray,
3516  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3517  &transdatums, NULL, &ndatums);
3518  if (ndatums != 2)
3519  elog(ERROR, "expected 2-element interval array");
3520 
3521  sumX = *(DatumGetIntervalP(transdatums[0]));
3522  N = *(DatumGetIntervalP(transdatums[1]));
3523 
3525  IntervalPGetDatum(&sumX),
3526  IntervalPGetDatum(newval)));
3527  N.time -= 1;
3528 
3529  transdatums[0] = IntervalPGetDatum(newsum);
3530  transdatums[1] = IntervalPGetDatum(&N);
3531 
3532  result = construct_array(transdatums, 2,
3533  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE);
3534 
3535  PG_RETURN_ARRAYTYPE_P(result);
3536 }
3537 
3538 Datum
3540 {
3541  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3542  Datum *transdatums;
3543  int ndatums;
3544  Interval sumX,
3545  N;
3546 
3547  deconstruct_array(transarray,
3548  INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3549  &transdatums, NULL, &ndatums);
3550  if (ndatums != 2)
3551  elog(ERROR, "expected 2-element interval array");
3552 
3553  sumX = *(DatumGetIntervalP(transdatums[0]));
3554  N = *(DatumGetIntervalP(transdatums[1]));
3555 
3556  /* SQL defines AVG of no values to be NULL */
3557  if (N.time == 0)
3558  PG_RETURN_NULL();
3559 
3561  IntervalPGetDatum(&sumX),
3562  Float8GetDatum((double) N.time));
3563 }
3564 
3565 
3566 /* timestamp_age()
3567  * Calculate time difference while retaining year/month fields.
3568  * Note that this does not result in an accurate absolute time span
3569  * since year and month are out of context once the arithmetic
3570  * is done.
3571  */
3572 Datum
3574 {
3575  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
3576  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
3577  Interval *result;
3578  fsec_t fsec,
3579  fsec1,
3580  fsec2;
3581  struct pg_tm tt,
3582  *tm = &tt;
3583  struct pg_tm tt1,
3584  *tm1 = &tt1;
3585  struct pg_tm tt2,
3586  *tm2 = &tt2;
3587 
3588  result = (Interval *) palloc(sizeof(Interval));
3589 
3590  if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
3591  timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
3592  {
3593  /* form the symbolic difference */
3594  fsec = fsec1 - fsec2;
3595  tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
3596  tm->tm_min = tm1->tm_min - tm2->tm_min;
3597  tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
3598  tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
3599  tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
3600  tm->tm_year = tm1->tm_year - tm2->tm_year;
3601 
3602  /* flip sign if necessary... */
3603  if (dt1 < dt2)
3604  {
3605  fsec = -fsec;
3606  tm->tm_sec = -tm->tm_sec;
3607  tm->tm_min = -tm->tm_min;
3608  tm->tm_hour = -tm->tm_hour;
3609  tm->tm_mday = -tm->tm_mday;
3610  tm->tm_mon = -tm->tm_mon;
3611  tm->tm_year = -tm->tm_year;
3612  }
3613 
3614  /* propagate any negative fields into the next higher field */
3615  while (fsec < 0)
3616  {
3617  fsec += USECS_PER_SEC;
3618  tm->tm_sec--;
3619  }
3620 
3621  while (tm->tm_sec < 0)
3622  {
3623  tm->tm_sec += SECS_PER_MINUTE;
3624  tm->tm_min--;
3625  }
3626 
3627  while (tm->tm_min < 0)
3628  {
3629  tm->tm_min += MINS_PER_HOUR;
3630  tm->tm_hour--;
3631  }
3632 
3633  while (tm->tm_hour < 0)
3634  {
3635  tm->tm_hour += HOURS_PER_DAY;
3636  tm->tm_mday--;
3637  }
3638 
3639  while (tm->tm_mday < 0)
3640  {
3641  if (dt1 < dt2)
3642  {
3643  tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
3644  tm->tm_mon--;
3645  }
3646  else
3647  {
3648  tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
3649  tm->tm_mon--;
3650  }
3651  }
3652 
3653  while (tm->tm_mon < 0)
3654  {
3655  tm->tm_mon += MONTHS_PER_YEAR;
3656  tm->tm_year--;
3657  }
3658 
3659  /* recover sign if necessary... */
3660  if (dt1 < dt2)
3661  {
3662  fsec = -fsec;
3663  tm->tm_sec = -tm->tm_sec;
3664  tm->tm_min = -tm->tm_min;
3665  tm->tm_hour = -tm->tm_hour;
3666  tm->tm_mday = -tm->tm_mday;
3667  tm->tm_mon = -tm->tm_mon;
3668  tm->tm_year = -tm->tm_year;
3669  }
3670 
3671  if (tm2interval(tm, fsec, result) != 0)
3672  ereport(ERROR,
3673  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3674  errmsg("interval out of range")));
3675  }
3676  else
3677  ereport(ERROR,
3678  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3679  errmsg("timestamp out of range")));
3680 
3681  PG_RETURN_INTERVAL_P(result);
3682 }
3683 
3684 
3685 /* timestamptz_age()
3686  * Calculate time difference while retaining year/month fields.
3687  * Note that this does not result in an accurate absolute time span
3688  * since year and month are out of context once the arithmetic
3689  * is done.
3690  */
3691 Datum
3693 {
3696  Interval *result;
3697  fsec_t fsec,
3698  fsec1,
3699  fsec2;
3700  struct pg_tm tt,
3701  *tm = &tt;
3702  struct pg_tm tt1,
3703  *tm1 = &tt1;
3704  struct pg_tm tt2,
3705  *tm2 = &tt2;
3706  int tz1;
3707  int tz2;
3708 
3709  result = (Interval *) palloc(sizeof(Interval));
3710 
3711  if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
3712  timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
3713  {
3714  /* form the symbolic difference */
3715  fsec = fsec1 - fsec2;
3716  tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
3717  tm->tm_min = tm1->tm_min - tm2->tm_min;
3718  tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
3719  tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
3720  tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
3721  tm->tm_year = tm1->tm_year - tm2->tm_year;
3722 
3723  /* flip sign if necessary... */
3724  if (dt1 < dt2)
3725  {
3726  fsec = -fsec;
3727  tm->tm_sec = -tm->tm_sec;
3728  tm->tm_min = -tm->tm_min;
3729  tm->tm_hour = -tm->tm_hour;
3730  tm->tm_mday = -tm->tm_mday;
3731  tm->tm_mon = -tm->tm_mon;
3732  tm->tm_year = -tm->tm_year;
3733  }
3734 
3735  /* propagate any negative fields into the next higher field */
3736  while (fsec < 0)
3737  {
3738  fsec += USECS_PER_SEC;
3739  tm->tm_sec--;
3740  }
3741 
3742  while (tm->tm_sec < 0)
3743  {
3744  tm->tm_sec += SECS_PER_MINUTE;
3745  tm->tm_min--;
3746  }
3747 
3748  while (tm->tm_min < 0)
3749  {
3750  tm->tm_min += MINS_PER_HOUR;
3751  tm->tm_hour--;
3752  }
3753 
3754  while (tm->tm_hour < 0)
3755  {
3756  tm->tm_hour += HOURS_PER_DAY;
3757  tm->tm_mday--;
3758  }
3759 
3760  while (tm->tm_mday < 0)
3761  {
3762  if (dt1 < dt2)
3763  {
3764  tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
3765  tm->tm_mon--;
3766  }
3767  else
3768  {
3769  tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
3770  tm->tm_mon--;
3771  }
3772  }
3773 
3774  while (tm->tm_mon < 0)
3775  {
3776  tm->tm_mon += MONTHS_PER_YEAR;
3777  tm->tm_year--;
3778  }
3779 
3780  /*
3781  * Note: we deliberately ignore any difference between tz1 and tz2.
3782  */
3783 
3784  /* recover sign if necessary... */
3785  if (dt1 < dt2)
3786  {
3787  fsec = -fsec;
3788  tm->tm_sec = -tm->tm_sec;
3789  tm->tm_min = -tm->tm_min;
3790  tm->tm_hour = -tm->tm_hour;
3791  tm->tm_mday = -tm->tm_mday;
3792  tm->tm_mon = -tm->tm_mon;
3793  tm->tm_year = -tm->tm_year;
3794  }
3795 
3796  if (tm2interval(tm, fsec, result) != 0)
3797  ereport(ERROR,
3798  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3799  errmsg("interval out of range")));
3800  }
3801  else
3802  ereport(ERROR,
3803  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3804  errmsg("timestamp out of range")));
3805 
3806  PG_RETURN_INTERVAL_P(result);
3807 }
3808 
3809 
3810 /*----------------------------------------------------------
3811  * Conversion operators.
3812  *---------------------------------------------------------*/
3813 
3814 
3815 /* timestamp_trunc()
3816  * Truncate timestamp to specified units.
3817  */
3818 Datum
3820 {
3821  text *units = PG_GETARG_TEXT_PP(0);
3823  Timestamp result;
3824  int type,
3825  val;
3826  char *lowunits;
3827  fsec_t fsec;
3828  struct pg_tm tt,
3829  *tm = &tt;
3830 
3831  if (TIMESTAMP_NOT_FINITE(timestamp))
3832  PG_RETURN_TIMESTAMP(timestamp);
3833 
3834  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3835  VARSIZE_ANY_EXHDR(units),
3836  false);
3837 
3838  type = DecodeUnits(0, lowunits, &val);
3839 
3840  if (type == UNITS)
3841  {
3842  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3843  ereport(ERROR,
3844  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3845  errmsg("timestamp out of range")));
3846 
3847  switch (val)
3848  {
3849  case DTK_WEEK:
3850  {
3851  int woy;
3852 
3853  woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
3854 
3855  /*
3856  * If it is week 52/53 and the month is January, then the
3857  * week must belong to the previous year. Also, some
3858  * December dates belong to the next year.
3859  */
3860  if (woy >= 52 && tm->tm_mon == 1)
3861  --tm->tm_year;
3862  if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
3863  ++tm->tm_year;
3864  isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
3865  tm->tm_hour = 0;
3866  tm->tm_min = 0;
3867  tm->tm_sec = 0;
3868  fsec = 0;
3869  break;
3870  }
3871  case DTK_MILLENNIUM:
3872  /* see comments in timestamptz_trunc */
3873  if (tm->tm_year > 0)
3874  tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
3875  else
3876  tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
3877  /* FALL THRU */
3878  case DTK_CENTURY:
3879  /* see comments in timestamptz_trunc */
3880  if (tm->tm_year > 0)
3881  tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
3882  else
3883  tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
3884  /* FALL THRU */
3885  case DTK_DECADE:
3886  /* see comments in timestamptz_trunc */
3887  if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
3888  {
3889  if (tm->tm_year > 0)
3890  tm->tm_year = (tm->tm_year / 10) * 10;
3891  else
3892  tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
3893  }
3894  /* FALL THRU */
3895  case DTK_YEAR:
3896  tm->tm_mon = 1;
3897  /* FALL THRU */
3898  case DTK_QUARTER:
3899  tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
3900  /* FALL THRU */
3901  case DTK_MONTH:
3902  tm->tm_mday = 1;
3903  /* FALL THRU */
3904  case DTK_DAY:
3905  tm->tm_hour = 0;
3906  /* FALL THRU */
3907  case DTK_HOUR:
3908  tm->tm_min = 0;
3909  /* FALL THRU */
3910  case DTK_MINUTE:
3911  tm->tm_sec = 0;
3912  /* FALL THRU */
3913  case DTK_SECOND:
3914  fsec = 0;
3915  break;
3916 
3917  case DTK_MILLISEC:
3918  fsec = (fsec / 1000) * 1000;
3919  break;
3920 
3921  case DTK_MICROSEC:
3922  break;
3923 
3924  default:
3925  ereport(ERROR,
3926  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3927  errmsg("timestamp units \"%s\" not supported",
3928  lowunits)));
3929  result = 0;
3930  }
3931 
3932  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
3933  ereport(ERROR,
3934  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3935  errmsg("timestamp out of range")));
3936  }
3937  else
3938  {
3939  ereport(ERROR,
3940  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3941  errmsg("timestamp units \"%s\" not recognized",
3942  lowunits)));
3943  result = 0;
3944  }
3945 
3946  PG_RETURN_TIMESTAMP(result);
3947 }
3948 
3949 /*
3950  * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
3951  *
3952  * tzp identifies the zone to truncate with respect to. We assume
3953  * infinite timestamps have already been rejected.
3954  */
3955 static TimestampTz
3957 {
3958  TimestampTz result;
3959  int tz;
3960  int type,
3961  val;
3962  bool redotz = false;
3963  char *lowunits;
3964  fsec_t fsec;
3965  struct pg_tm tt,
3966  *tm = &tt;
3967 
3968  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3969  VARSIZE_ANY_EXHDR(units),
3970  false);
3971 
3972  type = DecodeUnits(0, lowunits, &val);
3973 
3974  if (type == UNITS)
3975  {
3976  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
3977  ereport(ERROR,
3978  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3979  errmsg("timestamp out of range")));
3980 
3981  switch (val)
3982  {
3983  case DTK_WEEK:
3984  {
3985  int woy;
3986 
3987  woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
3988 
3989  /*
3990  * If it is week 52/53 and the month is January, then the
3991  * week must belong to the previous year. Also, some
3992  * December dates belong to the next year.
3993  */
3994  if (woy >= 52 && tm->tm_mon == 1)
3995  --tm->tm_year;
3996  if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
3997  ++tm->tm_year;
3998  isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
3999  tm->tm_hour = 0;
4000  tm->tm_min = 0;
4001  tm->tm_sec = 0;
4002  fsec = 0;
4003  redotz = true;
4004  break;
4005  }
4006  /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
4007  case DTK_MILLENNIUM:
4008 
4009  /*
4010  * truncating to the millennium? what is this supposed to
4011  * mean? let us put the first year of the millennium... i.e.
4012  * -1000, 1, 1001, 2001...
4013  */
4014  if (tm->tm_year > 0)
4015  tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4016  else
4017  tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4018  /* FALL THRU */
4019  case DTK_CENTURY:
4020  /* truncating to the century? as above: -100, 1, 101... */
4021  if (tm->tm_year > 0)
4022  tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4023  else
4024  tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4025  /* FALL THRU */
4026  case DTK_DECADE:
4027 
4028  /*
4029  * truncating to the decade? first year of the decade. must
4030  * not be applied if year was truncated before!
4031  */
4032  if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4033  {
4034  if (tm->tm_year > 0)
4035  tm->tm_year = (tm->tm_year / 10) * 10;
4036  else
4037  tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4038  }
4039  /* FALL THRU */
4040  case DTK_YEAR:
4041  tm->tm_mon = 1;
4042  /* FALL THRU */
4043  case DTK_QUARTER:
4044  tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4045  /* FALL THRU */
4046  case DTK_MONTH:
4047  tm->tm_mday = 1;
4048  /* FALL THRU */
4049  case DTK_DAY:
4050  tm->tm_hour = 0;
4051  redotz = true; /* for all cases >= DAY */
4052  /* FALL THRU */
4053  case DTK_HOUR:
4054  tm->tm_min = 0;
4055  /* FALL THRU */
4056  case DTK_MINUTE:
4057  tm->tm_sec = 0;
4058  /* FALL THRU */
4059  case DTK_SECOND:
4060  fsec = 0;
4061  break;
4062  case DTK_MILLISEC:
4063  fsec = (fsec / 1000) * 1000;
4064  break;
4065  case DTK_MICROSEC:
4066  break;
4067 
4068  default:
4069  ereport(ERROR,
4070  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4071  errmsg("timestamp with time zone units \"%s\" not "
4072  "supported", lowunits)));
4073  result = 0;
4074  }
4075 
4076  if (redotz)
4077  tz = DetermineTimeZoneOffset(tm, tzp);
4078 
4079  if (tm2timestamp(tm, fsec, &tz, &result) != 0)
4080  ereport(ERROR,
4081  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4082  errmsg("timestamp out of range")));
4083  }
4084  else
4085  {
4086  ereport(ERROR,
4087  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4088  errmsg("timestamp with time zone units \"%s\" not recognized",
4089  lowunits)));
4090  result = 0;
4091  }
4092 
4093  return result;
4094 }
4095 
4096 /* timestamptz_trunc()
4097  * Truncate timestamptz to specified units in session timezone.
4098  */
4099 Datum
4101 {
4102  text *units = PG_GETARG_TEXT_PP(0);
4104  TimestampTz result;
4105 
4106  if (TIMESTAMP_NOT_FINITE(timestamp))
4107  PG_RETURN_TIMESTAMPTZ(timestamp);
4108 
4109  result = timestamptz_trunc_internal(units, timestamp, session_timezone);
4110 
4111  PG_RETURN_TIMESTAMPTZ(result);
4112 }
4113 
4114 /* timestamptz_trunc_zone()
4115  * Truncate timestamptz to specified units in specified timezone.
4116  */
4117 Datum
4119 {
4120  text *units = PG_GETARG_TEXT_PP(0);
4122  text *zone = PG_GETARG_TEXT_PP(2);
4123  TimestampTz result;
4124  char tzname[TZ_STRLEN_MAX + 1];
4125  char *lowzone;
4126  int type,
4127  val;
4128  pg_tz *tzp;
4129 
4130  /*
4131  * timestamptz_zone() doesn't look up the zone for infinite inputs, so we
4132  * don't do so here either.
4133  */
4134  if (TIMESTAMP_NOT_FINITE(timestamp))
4135  PG_RETURN_TIMESTAMP(timestamp);
4136 
4137  /*
4138  * Look up the requested timezone (see notes in timestamptz_zone()).
4139  */
4140  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
4141 
4142  /* DecodeTimezoneAbbrev requires lowercase input */
4143  lowzone = downcase_truncate_identifier(tzname,
4144  strlen(tzname),
4145  false);
4146 
4147  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
4148 
4149  if (type == TZ || type == DTZ)
4150  {
4151  /* fixed-offset abbreviation, get a pg_tz descriptor for that */
4152  tzp = pg_tzset_offset(-val);
4153  }
4154  else if (type == DYNTZ)
4155  {
4156  /* dynamic-offset abbreviation, use its referenced timezone */
4157  }
4158  else
4159  {
4160  /* try it as a full zone name */
4161  tzp = pg_tzset(tzname);
4162  if (!tzp)
4163  ereport(ERROR,
4164  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4165  errmsg("time zone \"%s\" not recognized", tzname)));
4166  }
4167 
4168  result = timestamptz_trunc_internal(units, timestamp, tzp);
4169 
4170  PG_RETURN_TIMESTAMPTZ(result);
4171 }
4172 
4173 /* interval_trunc()
4174  * Extract specified field from interval.
4175  */
4176 Datum
4178 {
4179  text *units = PG_GETARG_TEXT_PP(0);
4181  Interval *result;
4182  int type,
4183  val;
4184  char *lowunits;
4185  fsec_t fsec;
4186  struct pg_tm tt,
4187  *tm = &tt;
4188 
4189  result = (Interval *) palloc(sizeof(Interval));
4190 
4191  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4192  VARSIZE_ANY_EXHDR(units),
4193  false);
4194 
4195  type = DecodeUnits(0, lowunits, &val);
4196 
4197  if (type == UNITS)
4198  {
4199  if (interval2tm(*interval, tm, &fsec) == 0)
4200  {
4201  switch (val)
4202  {
4203  case DTK_MILLENNIUM:
4204  /* caution: C division may have negative remainder */
4205  tm->tm_year = (tm->tm_year / 1000) * 1000;
4206  /* FALL THRU */
4207  case DTK_CENTURY:
4208  /* caution: C division may have negative remainder */
4209  tm->tm_year = (tm->tm_year / 100) * 100;
4210  /* FALL THRU */
4211  case DTK_DECADE:
4212  /* caution: C division may have negative remainder */
4213  tm->tm_year = (tm->tm_year / 10) * 10;
4214  /* FALL THRU */
4215  case DTK_YEAR:
4216  tm->tm_mon = 0;
4217  /* FALL THRU */
4218  case DTK_QUARTER:
4219  tm->tm_mon = 3 * (tm->tm_mon / 3);
4220  /* FALL THRU */
4221  case DTK_MONTH:
4222  tm->tm_mday = 0;
4223  /* FALL THRU */
4224  case DTK_DAY:
4225  tm->tm_hour = 0;
4226  /* FALL THRU */
4227  case DTK_HOUR:
4228  tm->tm_min = 0;
4229  /* FALL THRU */
4230  case DTK_MINUTE:
4231  tm->tm_sec = 0;
4232  /* FALL THRU */
4233  case DTK_SECOND:
4234  fsec = 0;
4235  break;
4236  case DTK_MILLISEC:
4237  fsec = (fsec / 1000) * 1000;
4238  break;
4239  case DTK_MICROSEC:
4240  break;
4241 
4242  default:
4243  if (val == DTK_WEEK)
4244  ereport(ERROR,
4245  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4246  errmsg("interval units \"%s\" not supported "
4247  "because months usually have fractional weeks",
4248  lowunits)));
4249  else
4250  ereport(ERROR,
4251  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4252  errmsg("interval units \"%s\" not supported",
4253  lowunits)));
4254  }
4255 
4256  if (tm2interval(tm, fsec, result) != 0)
4257  ereport(ERROR,
4258  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4259  errmsg("interval out of range")));
4260  }
4261  else
4262  elog(ERROR, "could not convert interval to tm");
4263  }
4264  else
4265  {
4266  ereport(ERROR,
4267  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4268  errmsg("interval units \"%s\" not recognized",
4269  lowunits)));
4270  }
4271 
4272  PG_RETURN_INTERVAL_P(result);
4273 }
4274 
4275 /* isoweek2j()
4276  *
4277  * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
4278  * Julian days are used to convert between ISO week dates and Gregorian dates.
4279  */
4280 int
4281 isoweek2j(int year, int week)
4282 {
4283  int day0,
4284  day4;
4285 
4286  /* fourth day of current year */
4287  day4 = date2j(year, 1, 4);
4288 
4289  /* day0 == offset to first day of week (Monday) */
4290  day0 = j2day(day4 - 1);
4291 
4292  return ((week - 1) * 7) + (day4 - day0);
4293 }
4294 
4295 /* isoweek2date()
4296  * Convert ISO week of year number to date.
4297  * The year field must be specified with the ISO year!
4298  * karel 2000/08/07
4299  */
4300 void
4301 isoweek2date(int woy, int *year, int *mon, int *mday)
4302 {
4303  j2date(isoweek2j(*year, woy), year, mon, mday);
4304 }
4305 
4306 /* isoweekdate2date()
4307  *
4308  * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
4309  * Gregorian day of week sent so weekday strings can be supplied.
4310  * Populates year, mon, and mday with the correct Gregorian values.
4311  * year must be passed in as the ISO year.
4312  */
4313 void
4314 isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
4315 {
4316  int jday;
4317 
4318  jday = isoweek2j(*year, isoweek);
4319  /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
4320  if (wday > 1)
4321  jday += wday - 2;
4322  else
4323  jday += 6;
4324  j2date(jday, year, mon, mday);
4325 }
4326 
4327 /* date2isoweek()
4328  *
4329  * Returns ISO week number of year.
4330  */
4331 int
4332 date2isoweek(int year, int mon, int mday)
4333 {
4334  float8 result;
4335  int day0,
4336  day4,
4337  dayn;
4338 
4339  /* current day */
4340  dayn = date2j(year, mon, mday);
4341 
4342  /* fourth day of current year */
4343  day4 = date2j(year, 1, 4);
4344 
4345  /* day0 == offset to first day of week (Monday) */
4346  day0 = j2day(day4 - 1);
4347 
4348  /*
4349  * We need the first week containing a Thursday, otherwise this day falls
4350  * into the previous year for purposes of counting weeks
4351  */
4352  if (dayn < day4 - day0)
4353  {
4354  day4 = date2j(year - 1, 1, 4);
4355 
4356  /* day0 == offset to first day of week (Monday) */
4357  day0 = j2day(day4 - 1);
4358  }
4359 
4360  result = (dayn - (day4 - day0)) / 7 + 1;
4361 
4362  /*
4363  * Sometimes the last few days in a year will fall into the first week of
4364  * the next year, so check for this.
4365  */
4366  if (result >= 52)
4367  {
4368  day4 = date2j(year + 1, 1, 4);
4369 
4370  /* day0 == offset to first day of week (Monday) */
4371  day0 = j2day(day4 - 1);
4372 
4373  if (dayn >= day4 - day0)
4374  result = (dayn - (day4 - day0)) / 7 + 1;
4375  }
4376 
4377  return (int) result;
4378 }
4379 
4380 
4381 /* date2isoyear()
4382  *
4383  * Returns ISO 8601 year number.
4384  * Note: zero or negative results follow the year-zero-exists convention.
4385  */
4386 int
4387 date2isoyear(int year, int mon, int mday)
4388 {
4389  float8 result;
4390  int day0,
4391  day4,
4392  dayn;
4393 
4394  /* current day */
4395  dayn = date2j(year, mon, mday);
4396 
4397  /* fourth day of current year */
4398  day4 = date2j(year, 1, 4);
4399 
4400  /* day0 == offset to first day of week (Monday) */
4401  day0 = j2day(day4 - 1);
4402 
4403  /*
4404  * We need the first week containing a Thursday, otherwise this day falls
4405  * into the previous year for purposes of counting weeks
4406  */
4407  if (dayn < day4 - day0)
4408  {
4409  day4 = date2j(year - 1, 1, 4);
4410 
4411  /* day0 == offset to first day of week (Monday) */
4412  day0 = j2day(day4 - 1);
4413 
4414  year--;
4415  }
4416 
4417  result = (dayn - (day4 - day0)) / 7 + 1;
4418 
4419  /*
4420  * Sometimes the last few days in a year will fall into the first week of
4421  * the next year, so check for this.
4422  */
4423  if (result >= 52)
4424  {
4425  day4 = date2j(year + 1, 1, 4);
4426 
4427  /* day0 == offset to first day of week (Monday) */
4428  day0 = j2day(day4 - 1);
4429 
4430  if (dayn >= day4 - day0)
4431  year++;
4432  }
4433 
4434  return year;
4435 }
4436 
4437 
4438 /* date2isoyearday()
4439  *
4440  * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
4441  * Possible return values are 1 through 371 (364 in non-leap years).
4442  */
4443 int
4444 date2isoyearday(int year, int mon, int mday)
4445 {
4446  return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
4447 }
4448 
4449 /*
4450  * NonFiniteTimestampTzPart
4451  *
4452  * Used by timestamp_part and timestamptz_part when extracting from infinite
4453  * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
4454  * otherwise returns zero (which should be taken as meaning to return NULL).
4455  *
4456  * Errors thrown here for invalid units should exactly match those that
4457  * would be thrown in the calling functions, else there will be unexpected
4458  * discrepancies between finite- and infinite-input cases.
4459  */
4460 static float8
4461 NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
4462  bool isNegative, bool isTz)
4463 {
4464  if ((type != UNITS) && (type != RESERV))
4465  {
4466  if (isTz)
4467  ereport(ERROR,
4468  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4469  errmsg("timestamp with time zone units \"%s\" not recognized",
4470  lowunits)));
4471  else
4472  ereport(ERROR,
4473  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4474  errmsg("timestamp units \"%s\" not recognized",
4475  lowunits)));
4476  }
4477 
4478  switch (unit)
4479  {
4480  /* Oscillating units */
4481  case DTK_MICROSEC:
4482  case DTK_MILLISEC:
4483  case DTK_SECOND:
4484  case DTK_MINUTE:
4485  case DTK_HOUR:
4486  case DTK_DAY:
4487  case DTK_MONTH:
4488  case DTK_QUARTER:
4489  case DTK_WEEK:
4490  case DTK_DOW:
4491  case DTK_ISODOW:
4492  case DTK_DOY:
4493  case DTK_TZ:
4494  case DTK_TZ_MINUTE:
4495  case DTK_TZ_HOUR:
4496  return 0.0;
4497 
4498  /* Monotonically-increasing units */
4499  case DTK_YEAR:
4500  case DTK_DECADE:
4501  case DTK_CENTURY:
4502  case DTK_MILLENNIUM:
4503  case DTK_JULIAN:
4504  case DTK_ISOYEAR:
4505  case DTK_EPOCH:
4506  if (isNegative)
4507  return -get_float8_infinity();
4508  else
4509  return get_float8_infinity();
4510 
4511  default:
4512  if (isTz)
4513  ereport(ERROR,
4514  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4515  errmsg("timestamp with time zone units \"%s\" not supported",
4516  lowunits)));
4517  else
4518  ereport(ERROR,
4519  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4520  errmsg("timestamp units \"%s\" not supported",
4521  lowunits)));
4522  return 0.0; /* keep compiler quiet */
4523  }
4524 }
4525 
4526 /* timestamp_part()
4527  * Extract specified field from timestamp.
4528  */
4529 Datum
4531 {
4532  text *units = PG_GETARG_TEXT_PP(0);
4534  float8 result;
4535  Timestamp epoch;
4536  int type,
4537  val;
4538  char *lowunits;
4539  fsec_t fsec;
4540  struct pg_tm tt,
4541  *tm = &tt;
4542 
4543  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4544  VARSIZE_ANY_EXHDR(units),
4545  false);
4546 
4547  type = DecodeUnits(0, lowunits, &val);
4548  if (type == UNKNOWN_FIELD)
4549  type = DecodeSpecial(0, lowunits, &val);
4550 
4551  if (TIMESTAMP_NOT_FINITE(timestamp))
4552  {
4553  result = NonFiniteTimestampTzPart(type, val, lowunits,
4554  TIMESTAMP_IS_NOBEGIN(timestamp),
4555  false);
4556  if (result)
4557  PG_RETURN_FLOAT8(result);
4558  else
4559  PG_RETURN_NULL();
4560  }
4561 
4562  if (type == UNITS)
4563  {
4564  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4565  ereport(ERROR,
4566  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4567  errmsg("timestamp out of range")));
4568 
4569  switch (val)
4570  {
4571  case DTK_MICROSEC:
4572  result = tm->tm_sec * 1000000.0 + fsec;
4573  break;
4574 
4575  case DTK_MILLISEC:
4576  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4577  break;
4578 
4579  case DTK_SECOND:
4580  result = tm->tm_sec + fsec / 1000000.0;
4581  break;
4582 
4583  case DTK_MINUTE:
4584  result = tm->tm_min;
4585  break;
4586 
4587  case DTK_HOUR:
4588  result = tm->tm_hour;
4589  break;
4590 
4591  case DTK_DAY:
4592  result = tm->tm_mday;
4593  break;
4594 
4595  case DTK_MONTH:
4596  result = tm->tm_mon;
4597  break;
4598 
4599  case DTK_QUARTER:
4600  result = (tm->tm_mon - 1) / 3 + 1;
4601  break;
4602 
4603  case DTK_WEEK:
4604  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4605  break;
4606 
4607  case DTK_YEAR:
4608  if (tm->tm_year > 0)
4609  result = tm->tm_year;
4610  else
4611  /* there is no year 0, just 1 BC and 1 AD */
4612  result = tm->tm_year - 1;
4613  break;
4614 
4615  case DTK_DECADE:
4616 
4617  /*
4618  * what is a decade wrt dates? let us assume that decade 199
4619  * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
4620  * is 11 BC thru 2 BC...
4621  */
4622  if (tm->tm_year >= 0)
4623  result = tm->tm_year / 10;
4624  else
4625  result = -((8 - (tm->tm_year - 1)) / 10);
4626  break;
4627 
4628  case DTK_CENTURY:
4629 
4630  /* ----
4631  * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
4632  * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
4633  * there is no number 0 century.
4634  * ----
4635  */
4636  if (tm->tm_year > 0)
4637  result = (tm->tm_year + 99) / 100;
4638  else
4639  /* caution: C division may have negative remainder */
4640  result = -((99 - (tm->tm_year - 1)) / 100);
4641  break;
4642 
4643  case DTK_MILLENNIUM:
4644  /* see comments above. */
4645  if (tm->tm_year > 0)
4646  result = (tm->tm_year + 999) / 1000;
4647  else
4648  result = -((999 - (tm->tm_year - 1)) / 1000);
4649  break;
4650 
4651  case DTK_JULIAN:
4652  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4653  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4654  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4655  break;
4656 
4657  case DTK_ISOYEAR:
4658  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4659  /* Adjust BC years */
4660  if (result <= 0)
4661  result -= 1;
4662  break;
4663 
4664  case DTK_DOW:
4665  case DTK_ISODOW:
4666  result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
4667  if (val == DTK_ISODOW && result == 0)
4668  result = 7;
4669  break;
4670 
4671  case DTK_DOY:
4672  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4673  - date2j(tm->tm_year, 1, 1) + 1);
4674  break;
4675 
4676  case DTK_TZ:
4677  case DTK_TZ_MINUTE:
4678  case DTK_TZ_HOUR:
4679  default:
4680  ereport(ERROR,
4681  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4682  errmsg("timestamp units \"%s\" not supported",
4683  lowunits)));
4684  result = 0;
4685  }
4686  }
4687  else if (type == RESERV)
4688  {
4689  switch (val)
4690  {
4691  case DTK_EPOCH:
4692  epoch = SetEpochTimestamp();
4693  /* try to avoid precision loss in subtraction */
4694  if (timestamp < (PG_INT64_MAX + epoch))
4695  result = (timestamp - epoch) / 1000000.0;
4696  else
4697  result = ((float8) timestamp - epoch) / 1000000.0;
4698  break;
4699 
4700  default:
4701  ereport(ERROR,
4702  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4703  errmsg("timestamp units \"%s\" not supported",
4704  lowunits)));
4705  result = 0;
4706  }
4707 
4708  }
4709  else
4710  {
4711  ereport(ERROR,
4712  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4713  errmsg("timestamp units \"%s\" not recognized", lowunits)));
4714  result = 0;
4715  }
4716 
4717  PG_RETURN_FLOAT8(result);
4718 }
4719 
4720 /* timestamptz_part()
4721  * Extract specified field from timestamp with time zone.
4722  */
4723 Datum
4725 {
4726  text *units = PG_GETARG_TEXT_PP(0);
4728  float8 result;
4729  Timestamp epoch;
4730  int tz;
4731  int type,
4732  val;
4733  char *lowunits;
4734  double dummy;
4735  fsec_t fsec;
4736  struct pg_tm tt,
4737  *tm = &tt;
4738 
4739  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4740  VARSIZE_ANY_EXHDR(units),
4741  false);
4742 
4743  type = DecodeUnits(0, lowunits, &val);
4744  if (type == UNKNOWN_FIELD)
4745  type = DecodeSpecial(0, lowunits, &val);
4746 
4747  if (TIMESTAMP_NOT_FINITE(timestamp))
4748  {
4749  result = NonFiniteTimestampTzPart(type, val, lowunits,
4750  TIMESTAMP_IS_NOBEGIN(timestamp),
4751  true);
4752  if (result)
4753  PG_RETURN_FLOAT8(result);
4754  else
4755  PG_RETURN_NULL();
4756  }
4757 
4758  if (type == UNITS)
4759  {
4760  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
4761  ereport(ERROR,
4762  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4763  errmsg("timestamp out of range")));
4764 
4765  switch (val)
4766  {
4767  case DTK_TZ:
4768  result = -tz;
4769  break;
4770 
4771  case DTK_TZ_MINUTE:
4772  result = -tz;
4773  result /= MINS_PER_HOUR;
4774  FMODULO(result, dummy, (double) MINS_PER_HOUR);
4775  break;
4776 
4777  case DTK_TZ_HOUR:
4778  dummy = -tz;
4779  FMODULO(dummy, result, (double) SECS_PER_HOUR);
4780  break;
4781 
4782  case DTK_MICROSEC:
4783  result = tm->tm_sec * 1000000.0 + fsec;
4784  break;
4785 
4786  case DTK_MILLISEC:
4787  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4788  break;
4789 
4790  case DTK_SECOND:
4791  result = tm->tm_sec + fsec / 1000000.0;
4792  break;
4793 
4794  case DTK_MINUTE:
4795  result = tm->tm_min;
4796  break;
4797 
4798  case DTK_HOUR:
4799  result = tm->tm_hour;
4800  break;
4801 
4802  case DTK_DAY:
4803  result = tm->tm_mday;
4804  break;
4805 
4806  case DTK_MONTH:
4807  result = tm->tm_mon;
4808  break;
4809 
4810  case DTK_QUARTER:
4811  result = (tm->tm_mon - 1) / 3 + 1;
4812  break;
4813 
4814  case DTK_WEEK:
4815  result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4816  break;
4817 
4818  case DTK_YEAR:
4819  if (tm->tm_year > 0)
4820  result = tm->tm_year;
4821  else
4822  /* there is no year 0, just 1 BC and 1 AD */
4823  result = tm->tm_year - 1;
4824  break;
4825 
4826  case DTK_DECADE:
4827  /* see comments in timestamp_part */
4828  if (tm->tm_year > 0)
4829  result = tm->tm_year / 10;
4830  else
4831  result = -((8 - (tm->tm_year - 1)) / 10);
4832  break;
4833 
4834  case DTK_CENTURY:
4835  /* see comments in timestamp_part */
4836  if (tm->tm_year > 0)
4837  result = (tm->tm_year + 99) / 100;
4838  else
4839  result = -((99 - (tm->tm_year - 1)) / 100);
4840  break;
4841 
4842  case DTK_MILLENNIUM:
4843  /* see comments in timestamp_part */
4844  if (tm->tm_year > 0)
4845  result = (tm->tm_year + 999) / 1000;
4846  else
4847  result = -((999 - (tm->tm_year - 1)) / 1000);
4848  break;
4849 
4850  case DTK_JULIAN:
4851  result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4852  result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
4853  tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
4854  break;
4855 
4856  case DTK_ISOYEAR:
4857  result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
4858  /* Adjust BC years */
4859  if (result <= 0)
4860  result -= 1;
4861  break;
4862 
4863  case DTK_DOW:
4864  case DTK_ISODOW:
4865  result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
4866  if (val == DTK_ISODOW && result == 0)
4867  result = 7;
4868  break;
4869 
4870  case DTK_DOY:
4871  result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4872  - date2j(tm->tm_year, 1, 1) + 1);
4873  break;
4874 
4875  default:
4876  ereport(ERROR,
4877  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4878  errmsg("timestamp with time zone units \"%s\" not supported",
4879  lowunits)));
4880  result = 0;
4881  }
4882 
4883  }
4884  else if (type == RESERV)
4885  {
4886  switch (val)
4887  {
4888  case DTK_EPOCH:
4889  epoch = SetEpochTimestamp();
4890  /* try to avoid precision loss in subtraction */
4891  if (timestamp < (PG_INT64_MAX + epoch))
4892  result = (timestamp - epoch) / 1000000.0;
4893  else
4894  result = ((float8) timestamp - epoch) / 1000000.0;
4895  break;
4896 
4897  default:
4898  ereport(ERROR,
4899  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4900  errmsg("timestamp with time zone units \"%s\" not supported",
4901  lowunits)));
4902  result = 0;
4903  }
4904  }
4905  else
4906  {
4907  ereport(ERROR,
4908  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4909  errmsg("timestamp with time zone units \"%s\" not recognized",
4910  lowunits)));
4911 
4912  result = 0;
4913  }
4914 
4915  PG_RETURN_FLOAT8(result);
4916 }
4917 
4918 
4919 /* interval_part()
4920  * Extract specified field from interval.
4921  */
4922 Datum
4924 {
4925  text *units = PG_GETARG_TEXT_PP(0);
4927  float8 result;
4928  int type,
4929  val;
4930  char *lowunits;
4931  fsec_t fsec;
4932  struct pg_tm tt,
4933  *tm = &tt;
4934 
4935  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4936  VARSIZE_ANY_EXHDR(units),
4937  false);
4938 
4939  type = DecodeUnits(0, lowunits, &val);
4940  if (type == UNKNOWN_FIELD)
4941  type = DecodeSpecial(0, lowunits, &val);
4942 
4943  if (type == UNITS)
4944  {
4945  if (interval2tm(*interval, tm, &fsec) == 0)
4946  {
4947  switch (val)
4948  {
4949  case DTK_MICROSEC:
4950  result = tm->tm_sec * 1000000.0 + fsec;
4951  break;
4952 
4953  case DTK_MILLISEC:
4954  result = tm->tm_sec * 1000.0 + fsec / 1000.0;
4955  break;
4956 
4957  case DTK_SECOND:
4958  result = tm->tm_sec + fsec / 1000000.0;
4959  break;
4960 
4961  case DTK_MINUTE:
4962  result = tm->tm_min;
4963  break;
4964 
4965  case DTK_HOUR:
4966  result = tm->tm_hour;
4967  break;
4968 
4969  case DTK_DAY:
4970  result = tm->tm_mday;
4971  break;
4972 
4973  case DTK_MONTH:
4974  result = tm->tm_mon;
4975  break;
4976 
4977  case DTK_QUARTER:
4978  result = (tm->tm_mon / 3) + 1;
4979  break;
4980 
4981  case DTK_YEAR:
4982  result = tm->tm_year;
4983  break;
4984 
4985  case DTK_DECADE:
4986  /* caution: C division may have negative remainder */
4987  result = tm->tm_year / 10;
4988  break;
4989 
4990  case DTK_CENTURY:
4991  /* caution: C division may have negative remainder */
4992  result = tm->tm_year / 100;
4993  break;
4994 
4995  case DTK_MILLENNIUM:
4996  /* caution: C division may have negative remainder */
4997  result = tm->tm_year / 1000;
4998  break;
4999 
5000  default:
5001  ereport(ERROR,
5002  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5003  errmsg("interval units \"%s\" not supported",
5004  lowunits)));
5005  result = 0;
5006  }
5007 
5008  }
5009  else
5010  {
5011  elog(ERROR, "could not convert interval to tm");
5012  result = 0;
5013  }
5014  }
5015  else if (type == RESERV && val == DTK_EPOCH)
5016  {
5017  result = interval->time / 1000000.0;
5018  result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
5019  result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
5020  result += ((double) SECS_PER_DAY) * interval->day;
5021  }
5022  else
5023  {
5024  ereport(ERROR,
5025  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5026  errmsg("interval units \"%s\" not recognized",
5027  lowunits)));
5028  result = 0;
5029  }
5030 
5031  PG_RETURN_FLOAT8(result);
5032 }
5033 
5034 
5035 /* timestamp_zone()
5036  * Encode timestamp type with specified time zone.
5037  * This function is just timestamp2timestamptz() except instead of
5038  * shifting to the global timezone, we shift to the specified timezone.
5039  * This is different from the other AT TIME ZONE cases because instead
5040  * of shifting _to_ a new time zone, it sets the time to _be_ the
5041  * specified timezone.
5042  */
5043 Datum
5045 {
5046  text *zone = PG_GETARG_TEXT_PP(0);
5048  TimestampTz result;
5049  int tz;
5050  char tzname[TZ_STRLEN_MAX + 1];
5051  char *lowzone;
5052  int type,
5053  val;
5054  pg_tz *tzp;
5055  struct pg_tm tm;
5056  fsec_t fsec;
5057 
5058  if (TIMESTAMP_NOT_FINITE(timestamp))
5059  PG_RETURN_TIMESTAMPTZ(timestamp);
5060 
5061  /*
5062  * Look up the requested timezone. First we look in the timezone
5063  * abbreviation table (to handle cases like "EST"), and if that fails, we
5064  * look in the timezone database (to handle cases like
5065  * "America/New_York"). (This matches the order in which timestamp input
5066  * checks the cases; it's important because the timezone database unwisely
5067  * uses a few zone names that are identical to offset abbreviations.)
5068  */
5069  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5070 
5071  /* DecodeTimezoneAbbrev requires lowercase input */
5072  lowzone = downcase_truncate_identifier(tzname,
5073  strlen(tzname),
5074  false);
5075 
5076  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5077 
5078  if (type == TZ || type == DTZ)
5079  {
5080  /* fixed-offset abbreviation */
5081  tz = val;
5082  result = dt2local(timestamp, tz);
5083  }
5084  else if (type == DYNTZ)
5085  {
5086  /* dynamic-offset abbreviation, resolve using specified time */
5087  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5088  ereport(ERROR,
5089  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5090  errmsg("timestamp out of range")));
5091  tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
5092  result = dt2local(timestamp, tz);
5093  }
5094  else
5095  {
5096  /* try it as a full zone name */
5097  tzp = pg_tzset(tzname);
5098  if (tzp)
5099  {
5100  /* Apply the timezone change */
5101  if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
5102  ereport(ERROR,
5103  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5104  errmsg("timestamp out of range")));
5105  tz = DetermineTimeZoneOffset(&tm, tzp);
5106  if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
5107  ereport(ERROR,
5108  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5109  errmsg("timestamp out of range")));
5110  }
5111  else
5112  {
5113  ereport(ERROR,
5114  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5115  errmsg("time zone \"%s\" not recognized", tzname)));
5116  result = 0; /* keep compiler quiet */
5117  }
5118  }
5119 
5120  if (!IS_VALID_TIMESTAMP(result))
5121  ereport(ERROR,
5122  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5123  errmsg("timestamp out of range")));
5124 
5125  PG_RETURN_TIMESTAMPTZ(result);
5126 }
5127 
5128 /* timestamp_izone()
5129  * Encode timestamp type with specified time interval as time zone.
5130  */
5131 Datum
5133 {
5136  TimestampTz result;
5137  int tz;
5138 
5139  if (TIMESTAMP_NOT_FINITE(timestamp))
5140  PG_RETURN_TIMESTAMPTZ(timestamp);
5141 
5142  if (zone->month != 0 || zone->day != 0)
5143  ereport(ERROR,
5144  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5145  errmsg("interval time zone \"%s\" must not include months or days",
5147  PointerGetDatum(zone))))));
5148 
5149  tz = zone->time / USECS_PER_SEC;
5150 
5151  result = dt2local(timestamp, tz);
5152 
5153  if (!IS_VALID_TIMESTAMP(result))
5154  ereport(ERROR,
5155  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5156  errmsg("timestamp out of range")));
5157 
5158  PG_RETURN_TIMESTAMPTZ(result);
5159 } /* timestamp_izone() */
5160 
5161 /* TimestampTimestampTzRequiresRewrite()
5162  *
5163  * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
5164  * timestamptz_timestamp to be no-ops, where the return value has the same
5165  * bits as the argument. Since project convention is to assume a GUC changes
5166  * no more often than STABLE functions change, the answer is valid that long.
5167  */
5168 bool
5170 {
5171  long offset;
5172 
5173  if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
5174  return false;
5175  return true;
5176 }
5177 
5178 /* timestamp_timestamptz()
5179  * Convert local timestamp to timestamp at GMT
5180  */
5181 Datum
5183 {
5185 
5187 }
5188 
5189 /*
5190  * Convert timestamp to timestamp with time zone.
5191  *
5192  * On successful conversion, *overflow is set to zero if it's not NULL.
5193  *
5194  * If the timestamp is finite but out of the valid range for timestamptz, then:
5195  * if overflow is NULL, we throw an out-of-range error.
5196  * if overflow is not NULL, we store +1 or -1 there to indicate the sign
5197  * of the overflow, and return the appropriate timestamptz infinity.
5198  */
5201 {
5202  TimestampTz result;
5203  struct pg_tm tt,
5204  *tm = &tt;
5205  fsec_t fsec;
5206  int tz;
5207 
5208  if (overflow)
5209  *overflow = 0;
5210 
5211  if (TIMESTAMP_NOT_FINITE(timestamp))
5212  return timestamp;
5213 
5214  /* We don't expect this to fail, but check it pro forma */
5215  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
5216  {
5218 
5219  result = dt2local(timestamp, -tz);
5220 
5221  if (IS_VALID_TIMESTAMP(result))
5222  {
5223  return result;
5224  }
5225  else if (overflow)
5226  {
5227  if (result < MIN_TIMESTAMP)
5228  {
5229  *overflow = -1;
5230  TIMESTAMP_NOBEGIN(result);
5231  }
5232  else
5233  {
5234  *overflow = 1;
5235  TIMESTAMP_NOEND(result);
5236  }
5237  return result;
5238  }
5239  }
5240 
5241  ereport(ERROR,
5242  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5243  errmsg("timestamp out of range")));
5244 
5245  return 0;
5246 }
5247 
5248 /*
5249  * Promote timestamp to timestamptz, throwing error for overflow.
5250  */
5251 static TimestampTz
5253 {
5254  return timestamp2timestamptz_opt_overflow(timestamp, NULL);
5255 }
5256 
5257 /* timestamptz_timestamp()
5258  * Convert timestamp at GMT to local timestamp
5259  */
5260 Datum
5262 {
5264 
5266 }
5267 
5268 static Timestamp
5270 {
5271  Timestamp result;
5272  struct pg_tm tt,
5273  *tm = &tt;
5274  fsec_t fsec;
5275  int tz;
5276 
5277  if (TIMESTAMP_NOT_FINITE(timestamp))
5278  result = timestamp;
5279  else
5280  {
5281  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5282  ereport(ERROR,
5283  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5284  errmsg("timestamp out of range")));
5285  if (tm2timestamp(tm, fsec, NULL, &result) != 0)
5286  ereport(ERROR,
5287  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5288  errmsg("timestamp out of range")));
5289  }
5290  return result;
5291 }
5292 
5293 /* timestamptz_zone()
5294  * Evaluate timestamp with time zone type at the specified time zone.
5295  * Returns a timestamp without time zone.
5296  */
5297 Datum
5299 {
5300  text *zone = PG_GETARG_TEXT_PP(0);
5302  Timestamp result;
5303  int tz;
5304  char tzname[TZ_STRLEN_MAX + 1];
5305  char *lowzone;
5306  int type,
5307  val;
5308  pg_tz *tzp;
5309 
5310  if (TIMESTAMP_NOT_FINITE(timestamp))
5311  PG_RETURN_TIMESTAMP(timestamp);
5312 
5313  /*
5314  * Look up the requested timezone. First we look in the timezone
5315  * abbreviation table (to handle cases like "EST"), and if that fails, we
5316  * look in the timezone database (to handle cases like
5317  * "America/New_York"). (This matches the order in which timestamp input
5318  * checks the cases; it's important because the timezone database unwisely
5319  * uses a few zone names that are identical to offset abbreviations.)
5320  */
5321  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5322 
5323  /* DecodeTimezoneAbbrev requires lowercase input */
5324  lowzone = downcase_truncate_identifier(tzname,
5325  strlen(tzname),
5326  false);
5327 
5328  type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
5329 
5330  if (type == TZ || type == DTZ)
5331  {
5332  /* fixed-offset abbreviation */
5333  tz = -val;
5334  result = dt2local(timestamp, tz);
5335  }
5336  else if (type == DYNTZ)
5337  {
5338  /* dynamic-offset abbreviation, resolve using specified time */
5339  int isdst;
5340 
5341  tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
5342  result = dt2local(timestamp, tz);
5343  }
5344  else
5345  {
5346  /* try it as a full zone name */
5347  tzp = pg_tzset(tzname);
5348  if (tzp)
5349  {
5350  /* Apply the timezone change */
5351  struct pg_tm tm;
5352  fsec_t fsec;
5353 
5354  if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
5355  ereport(ERROR,
5356  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5357  errmsg("timestamp out of range")));
5358  if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
5359  ereport(ERROR,
5360  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5361  errmsg("timestamp out of range")));
5362  }
5363  else
5364  {
5365  ereport(ERROR,
5366  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5367  errmsg("time zone \"%s\" not recognized", tzname)));
5368  result = 0; /* keep compiler quiet */
5369  }
5370  }
5371 
5372  if (!IS_VALID_TIMESTAMP(result))
5373  ereport(ERROR,
5374  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5375  errmsg("timestamp out of range")));
5376 
5377  PG_RETURN_TIMESTAMP(result);
5378 }
5379 
5380 /* timestamptz_izone()
5381  * Encode timestamp with time zone type with specified time interval as time zone.
5382  * Returns a timestamp without time zone.
5383  */
5384 Datum
5386 {
5389  Timestamp result;
5390  int tz;
5391 
5392  if (TIMESTAMP_NOT_FINITE(timestamp))
5393  PG_RETURN_TIMESTAMP(timestamp);
5394 
5395  if (zone->month != 0 || zone->day != 0)
5396  ereport(ERROR,
5397  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5398  errmsg("interval time zone \"%s\" must not include months or days",
5400  PointerGetDatum(zone))))));
5401 
5402  tz = -(zone->time / USECS_PER_SEC);
5403 
5404  result = dt2local(timestamp, tz);
5405 
5406  if (!IS_VALID_TIMESTAMP(result))
5407  ereport(ERROR,
5408  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5409  errmsg("timestamp out of range")));
5410 
5411  PG_RETURN_TIMESTAMP(result);
5412 }
5413 
5414 /* generate_series_timestamp()
5415  * Generate the set of timestamps from start to finish by step
5416  */
5417 Datum
5419 {
5420  FuncCallContext *funcctx;
5422  Timestamp result;
5423 
5424  /* stuff done only on the first call of the function */
5425  if (SRF_IS_FIRSTCALL())
5426  {
5427  Timestamp start = PG_GETARG_TIMESTAMP(0);
5428  Timestamp finish = PG_GETARG_TIMESTAMP(1);
5429  Interval *step = PG_GETARG_INTERVAL_P(2);
5430  MemoryContext oldcontext;
5431  Interval interval_zero;
5432 
5433  /* create a function context for cross-call persistence */
5434  funcctx = SRF_FIRSTCALL_INIT();
5435 
5436  /*
5437  * switch to memory context appropriate for multiple function calls
5438  */
5439  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5440 
5441  /* allocate memory for user context */
5444 
5445  /*
5446  * Use fctx to keep state from call to call. Seed current with the
5447  * original start value
5448  */
5449  fctx->current = start;
5450  fctx->finish = finish;
5451  fctx->step = *step;
5452 
5453  /* Determine sign of the interval */
5454  MemSet(&interval_zero, 0, sizeof(Interval));
5455  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5456 
5457  if (fctx->step_sign == 0)
5458  ereport(ERROR,
5459  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5460  errmsg("step size cannot equal zero")));
5461 
5462  funcctx->user_fctx = fctx;
5463  MemoryContextSwitchTo(oldcontext);
5464  }
5465 
5466  /* stuff done on every call of the function */
5467  funcctx = SRF_PERCALL_SETUP();
5468 
5469  /*
5470  * get the saved state and use current as the result for this iteration
5471  */
5472  fctx = funcctx->user_fctx;
5473  result = fctx->current;
5474 
5475  if (fctx->step_sign > 0 ?
5476  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5477  timestamp_cmp_internal(result, fctx->finish) >= 0)
5478  {
5479  /* increment current in preparation for next iteration */
5481  TimestampGetDatum(fctx->current),
5482  PointerGetDatum(&fctx->step)));
5483 
5484  /* do when there is more left to send */
5485  SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
5486  }
5487  else
5488  {
5489  /* do when there is no more left */
5490  SRF_RETURN_DONE(funcctx);
5491  }
5492 }
5493 
5494 /* generate_series_timestamptz()
5495  * Generate the set of timestamps from start to finish by step
5496  */
5497 Datum
5499 {
5500  FuncCallContext *funcctx;
5502  TimestampTz result;
5503 
5504  /* stuff done only on the first call of the function */
5505  if (SRF_IS_FIRSTCALL())
5506  {
5508  TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
5509  Interval *step = PG_GETARG_INTERVAL_P(2);
5510  MemoryContext oldcontext;
5511  Interval interval_zero;
5512 
5513  /* create a function context for cross-call persistence */
5514  funcctx = SRF_FIRSTCALL_INIT();
5515 
5516  /*
5517  * switch to memory context appropriate for multiple function calls
5518  */
5519  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5520 
5521  /* allocate memory for user context */
5524 
5525  /*
5526  * Use fctx to keep state from call to call. Seed current with the
5527  * original start value
5528  */
5529  fctx->current = start;
5530  fctx->finish = finish;
5531  fctx->step = *step;
5532 
5533  /* Determine sign of the interval */
5534  MemSet(&interval_zero, 0, sizeof(Interval));
5535  fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5536 
5537  if (fctx->step_sign == 0)
5538  ereport(ERROR,
5539  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5540  errmsg("step size cannot equal zero")));
5541 
5542  funcctx->user_fctx = fctx;
5543  MemoryContextSwitchTo(oldcontext);
5544  }
5545 
5546  /* stuff done on every call of the function */
5547  funcctx = SRF_PERCALL_SETUP();
5548 
5549  /*
5550  * get the saved state and use current as the result for this iteration
5551  */
5552  fctx = funcctx->user_fctx;
5553  result = fctx->current;
5554 
5555  if (fctx->step_sign > 0 ?
5556  timestamp_cmp_internal(result, fctx->finish) <= 0 :
5557  timestamp_cmp_internal(result, fctx->finish) >= 0)
5558  {
5559  /* increment current in preparation for next iteration */
5562  PointerGetDatum(&fctx->step)));
5563 
5564  /* do when there is more left to send */
5565  SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
5566  }
5567  else
5568  {
5569  /* do when there is no more left */
5570  SRF_RETURN_DONE(funcctx);
5571  }
5572 }
#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:2008
struct SortSupportData * SortSupport
Definition: sortsupport.h:58
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
Datum interval_smaller(PG_FUNCTION_ARGS)
Definition: timestamp.c:3074
Datum interval_justify_days(PG_FUNCTION_ARGS)
Definition: timestamp.c:2799
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
Datum in_range_interval_interval(PG_FUNCTION_ARGS)
Definition: timestamp.c:3378
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:3089
#define TIMESTAMP_NOEND(j)
Definition: timestamp.h:117
static TimestampTz timestamp2timestamptz(Timestamp timestamp)
Definition: timestamp.c:5252
Datum timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
Definition: timestamp.c:2321
Datum make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
Definition: timestamp.c:675
#define DTERR_BAD_FORMAT
Definition: