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