]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/date.c
Improve parsetree representation of special functions such as CURRENT_DATE.
[postgresql] / src / backend / utils / adt / date.c
1 /*-------------------------------------------------------------------------
2  *
3  * date.c
4  *        implements DATE and TIME data types specified in SQL standard
5  *
6  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994-5, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/utils/adt/date.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include <ctype.h>
19 #include <limits.h>
20 #include <float.h>
21 #include <time.h>
22
23 #include "access/hash.h"
24 #include "access/xact.h"
25 #include "libpq/pqformat.h"
26 #include "miscadmin.h"
27 #include "parser/scansup.h"
28 #include "utils/array.h"
29 #include "utils/builtins.h"
30 #include "utils/date.h"
31 #include "utils/datetime.h"
32 #include "utils/nabstime.h"
33 #include "utils/sortsupport.h"
34
35 /*
36  * gcc's -ffast-math switch breaks routines that expect exact results from
37  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
38  */
39 #ifdef __FAST_MATH__
40 #error -ffast-math is known to break this code
41 #endif
42
43
44 static int      time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
45 static int      timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
46 static int      tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
47 static int      tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
48 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
49
50
51 /* common code for timetypmodin and timetztypmodin */
52 static int32
53 anytime_typmodin(bool istz, ArrayType *ta)
54 {
55         int32      *tl;
56         int                     n;
57
58         tl = ArrayGetIntegerTypmods(ta, &n);
59
60         /*
61          * we're not too tense about good error message here because grammar
62          * shouldn't allow wrong number of modifiers for TIME
63          */
64         if (n != 1)
65                 ereport(ERROR,
66                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
67                                  errmsg("invalid type modifier")));
68
69         return anytime_typmod_check(istz, tl[0]);
70 }
71
72 /* exported so parse_expr.c can use it */
73 int32
74 anytime_typmod_check(bool istz, int32 typmod)
75 {
76         if (typmod < 0)
77                 ereport(ERROR,
78                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79                                  errmsg("TIME(%d)%s precision must not be negative",
80                                                 typmod, (istz ? " WITH TIME ZONE" : ""))));
81         if (typmod > MAX_TIME_PRECISION)
82         {
83                 ereport(WARNING,
84                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
85                                  errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
86                                                 typmod, (istz ? " WITH TIME ZONE" : ""),
87                                                 MAX_TIME_PRECISION)));
88                 typmod = MAX_TIME_PRECISION;
89         }
90
91         return typmod;
92 }
93
94 /* common code for timetypmodout and timetztypmodout */
95 static char *
96 anytime_typmodout(bool istz, int32 typmod)
97 {
98         const char *tz = istz ? " with time zone" : " without time zone";
99
100         if (typmod >= 0)
101                 return psprintf("(%d)%s", (int) typmod, tz);
102         else
103                 return psprintf("%s", tz);
104 }
105
106
107 /*****************************************************************************
108  *       Date ADT
109  *****************************************************************************/
110
111
112 /* date_in()
113  * Given date text string, convert to internal date format.
114  */
115 Datum
116 date_in(PG_FUNCTION_ARGS)
117 {
118         char       *str = PG_GETARG_CSTRING(0);
119         DateADT         date;
120         fsec_t          fsec;
121         struct pg_tm tt,
122                            *tm = &tt;
123         int                     tzp;
124         int                     dtype;
125         int                     nf;
126         int                     dterr;
127         char       *field[MAXDATEFIELDS];
128         int                     ftype[MAXDATEFIELDS];
129         char            workbuf[MAXDATELEN + 1];
130
131         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
132                                                   field, ftype, MAXDATEFIELDS, &nf);
133         if (dterr == 0)
134                 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
135         if (dterr != 0)
136                 DateTimeParseError(dterr, str, "date");
137
138         switch (dtype)
139         {
140                 case DTK_DATE:
141                         break;
142
143                 case DTK_CURRENT:
144                         ereport(ERROR,
145                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146                           errmsg("date/time value \"current\" is no longer supported")));
147
148                         GetCurrentDateTime(tm);
149                         break;
150
151                 case DTK_EPOCH:
152                         GetEpochTime(tm);
153                         break;
154
155                 case DTK_LATE:
156                         DATE_NOEND(date);
157                         PG_RETURN_DATEADT(date);
158
159                 case DTK_EARLY:
160                         DATE_NOBEGIN(date);
161                         PG_RETURN_DATEADT(date);
162
163                 default:
164                         DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
165                         break;
166         }
167
168         /* Prevent overflow in Julian-day routines */
169         if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
170                 ereport(ERROR,
171                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
172                                  errmsg("date out of range: \"%s\"", str)));
173
174         date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
175
176         /* Now check for just-out-of-range dates */
177         if (!IS_VALID_DATE(date))
178                 ereport(ERROR,
179                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
180                                  errmsg("date out of range: \"%s\"", str)));
181
182         PG_RETURN_DATEADT(date);
183 }
184
185 /* date_out()
186  * Given internal format date, convert to text string.
187  */
188 Datum
189 date_out(PG_FUNCTION_ARGS)
190 {
191         DateADT         date = PG_GETARG_DATEADT(0);
192         char       *result;
193         struct pg_tm tt,
194                            *tm = &tt;
195         char            buf[MAXDATELEN + 1];
196
197         if (DATE_NOT_FINITE(date))
198                 EncodeSpecialDate(date, buf);
199         else
200         {
201                 j2date(date + POSTGRES_EPOCH_JDATE,
202                            &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
203                 EncodeDateOnly(tm, DateStyle, buf);
204         }
205
206         result = pstrdup(buf);
207         PG_RETURN_CSTRING(result);
208 }
209
210 /*
211  *              date_recv                       - converts external binary format to date
212  */
213 Datum
214 date_recv(PG_FUNCTION_ARGS)
215 {
216         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
217         DateADT         result;
218
219         result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
220
221         /* Limit to the same range that date_in() accepts. */
222         if (DATE_NOT_FINITE(result))
223                  /* ok */ ;
224         else if (!IS_VALID_DATE(result))
225                 ereport(ERROR,
226                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
227                                  errmsg("date out of range")));
228
229         PG_RETURN_DATEADT(result);
230 }
231
232 /*
233  *              date_send                       - converts date to binary format
234  */
235 Datum
236 date_send(PG_FUNCTION_ARGS)
237 {
238         DateADT         date = PG_GETARG_DATEADT(0);
239         StringInfoData buf;
240
241         pq_begintypsend(&buf);
242         pq_sendint(&buf, date, sizeof(date));
243         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
244 }
245
246 /*
247  *              make_date                       - date constructor
248  */
249 Datum
250 make_date(PG_FUNCTION_ARGS)
251 {
252         struct pg_tm tm;
253         DateADT         date;
254         int                     dterr;
255
256         tm.tm_year = PG_GETARG_INT32(0);
257         tm.tm_mon = PG_GETARG_INT32(1);
258         tm.tm_mday = PG_GETARG_INT32(2);
259
260         /*
261          * Note: we'll reject zero or negative year values.  Perhaps negatives
262          * should be allowed to represent BC years?
263          */
264         dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
265
266         if (dterr != 0)
267                 ereport(ERROR,
268                                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
269                                  errmsg("date field value out of range: %d-%02d-%02d",
270                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
271
272         /* Prevent overflow in Julian-day routines */
273         if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
274                 ereport(ERROR,
275                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
276                                  errmsg("date out of range: %d-%02d-%02d",
277                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
278
279         date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
280
281         /* Now check for just-out-of-range dates */
282         if (!IS_VALID_DATE(date))
283                 ereport(ERROR,
284                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
285                                  errmsg("date out of range: %d-%02d-%02d",
286                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
287
288         PG_RETURN_DATEADT(date);
289 }
290
291 /*
292  * Convert reserved date values to string.
293  */
294 void
295 EncodeSpecialDate(DateADT dt, char *str)
296 {
297         if (DATE_IS_NOBEGIN(dt))
298                 strcpy(str, EARLY);
299         else if (DATE_IS_NOEND(dt))
300                 strcpy(str, LATE);
301         else    /* shouldn't happen */
302                 elog(ERROR, "invalid argument for EncodeSpecialDate");
303 }
304
305
306 /*
307  * GetSQLCurrentDate -- implements CURRENT_DATE
308  */
309 DateADT
310 GetSQLCurrentDate(void)
311 {
312         TimestampTz ts;
313         struct pg_tm tt,
314                            *tm = &tt;
315         fsec_t          fsec;
316         int                     tz;
317
318         ts = GetCurrentTransactionStartTimestamp();
319
320         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
321                 ereport(ERROR,
322                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
323                                  errmsg("timestamp out of range")));
324
325         return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
326 }
327
328 /*
329  * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
330  */
331 TimeTzADT *
332 GetSQLCurrentTime(int32 typmod)
333 {
334         TimeTzADT  *result;
335         TimestampTz ts;
336         struct pg_tm tt,
337                            *tm = &tt;
338         fsec_t          fsec;
339         int                     tz;
340
341         ts = GetCurrentTransactionStartTimestamp();
342
343         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
344                 ereport(ERROR,
345                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
346                                  errmsg("timestamp out of range")));
347
348         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
349         tm2timetz(tm, fsec, tz, result);
350         AdjustTimeForTypmod(&(result->time), typmod);
351         return result;
352 }
353
354 /*
355  * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
356  */
357 TimeADT
358 GetSQLLocalTime(int32 typmod)
359 {
360         TimeADT         result;
361         TimestampTz ts;
362         struct pg_tm tt,
363                            *tm = &tt;
364         fsec_t          fsec;
365         int                     tz;
366
367         ts = GetCurrentTransactionStartTimestamp();
368
369         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
370                 ereport(ERROR,
371                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
372                                  errmsg("timestamp out of range")));
373
374         tm2time(tm, fsec, &result);
375         AdjustTimeForTypmod(&result, typmod);
376         return result;
377 }
378
379
380 /*
381  * Comparison functions for dates
382  */
383
384 Datum
385 date_eq(PG_FUNCTION_ARGS)
386 {
387         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
388         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
389
390         PG_RETURN_BOOL(dateVal1 == dateVal2);
391 }
392
393 Datum
394 date_ne(PG_FUNCTION_ARGS)
395 {
396         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
397         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
398
399         PG_RETURN_BOOL(dateVal1 != dateVal2);
400 }
401
402 Datum
403 date_lt(PG_FUNCTION_ARGS)
404 {
405         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
406         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
407
408         PG_RETURN_BOOL(dateVal1 < dateVal2);
409 }
410
411 Datum
412 date_le(PG_FUNCTION_ARGS)
413 {
414         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
415         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
416
417         PG_RETURN_BOOL(dateVal1 <= dateVal2);
418 }
419
420 Datum
421 date_gt(PG_FUNCTION_ARGS)
422 {
423         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
424         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
425
426         PG_RETURN_BOOL(dateVal1 > dateVal2);
427 }
428
429 Datum
430 date_ge(PG_FUNCTION_ARGS)
431 {
432         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
433         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
434
435         PG_RETURN_BOOL(dateVal1 >= dateVal2);
436 }
437
438 Datum
439 date_cmp(PG_FUNCTION_ARGS)
440 {
441         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
442         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
443
444         if (dateVal1 < dateVal2)
445                 PG_RETURN_INT32(-1);
446         else if (dateVal1 > dateVal2)
447                 PG_RETURN_INT32(1);
448         PG_RETURN_INT32(0);
449 }
450
451 static int
452 date_fastcmp(Datum x, Datum y, SortSupport ssup)
453 {
454         DateADT         a = DatumGetDateADT(x);
455         DateADT         b = DatumGetDateADT(y);
456
457         if (a < b)
458                 return -1;
459         else if (a > b)
460                 return 1;
461         return 0;
462 }
463
464 Datum
465 date_sortsupport(PG_FUNCTION_ARGS)
466 {
467         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
468
469         ssup->comparator = date_fastcmp;
470         PG_RETURN_VOID();
471 }
472
473 Datum
474 date_finite(PG_FUNCTION_ARGS)
475 {
476         DateADT         date = PG_GETARG_DATEADT(0);
477
478         PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
479 }
480
481 Datum
482 date_larger(PG_FUNCTION_ARGS)
483 {
484         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
485         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
486
487         PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
488 }
489
490 Datum
491 date_smaller(PG_FUNCTION_ARGS)
492 {
493         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
494         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
495
496         PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
497 }
498
499 /* Compute difference between two dates in days.
500  */
501 Datum
502 date_mi(PG_FUNCTION_ARGS)
503 {
504         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
505         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
506
507         if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
508                 ereport(ERROR,
509                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
510                                  errmsg("cannot subtract infinite dates")));
511
512         PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
513 }
514
515 /* Add a number of days to a date, giving a new date.
516  * Must handle both positive and negative numbers of days.
517  */
518 Datum
519 date_pli(PG_FUNCTION_ARGS)
520 {
521         DateADT         dateVal = PG_GETARG_DATEADT(0);
522         int32           days = PG_GETARG_INT32(1);
523         DateADT         result;
524
525         if (DATE_NOT_FINITE(dateVal))
526                 PG_RETURN_DATEADT(dateVal);             /* can't change infinity */
527
528         result = dateVal + days;
529
530         /* Check for integer overflow and out-of-allowed-range */
531         if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
532                 !IS_VALID_DATE(result))
533                 ereport(ERROR,
534                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
535                                  errmsg("date out of range")));
536
537         PG_RETURN_DATEADT(result);
538 }
539
540 /* Subtract a number of days from a date, giving a new date.
541  */
542 Datum
543 date_mii(PG_FUNCTION_ARGS)
544 {
545         DateADT         dateVal = PG_GETARG_DATEADT(0);
546         int32           days = PG_GETARG_INT32(1);
547         DateADT         result;
548
549         if (DATE_NOT_FINITE(dateVal))
550                 PG_RETURN_DATEADT(dateVal);             /* can't change infinity */
551
552         result = dateVal - days;
553
554         /* Check for integer overflow and out-of-allowed-range */
555         if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
556                 !IS_VALID_DATE(result))
557                 ereport(ERROR,
558                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
559                                  errmsg("date out of range")));
560
561         PG_RETURN_DATEADT(result);
562 }
563
564 /*
565  * Internal routines for promoting date to timestamp and timestamp with
566  * time zone
567  */
568
569 static Timestamp
570 date2timestamp(DateADT dateVal)
571 {
572         Timestamp       result;
573
574         if (DATE_IS_NOBEGIN(dateVal))
575                 TIMESTAMP_NOBEGIN(result);
576         else if (DATE_IS_NOEND(dateVal))
577                 TIMESTAMP_NOEND(result);
578         else
579         {
580                 /*
581                  * Date's range is wider than timestamp's, so check for boundaries.
582                  * Since dates have the same minimum values as timestamps, only upper
583                  * boundary need be checked for overflow.
584                  */
585                 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
586                         ereport(ERROR,
587                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
588                                          errmsg("date out of range for timestamp")));
589 #ifdef HAVE_INT64_TIMESTAMP
590                 /* date is days since 2000, timestamp is microseconds since same... */
591                 result = dateVal * USECS_PER_DAY;
592 #else
593                 /* date is days since 2000, timestamp is seconds since same... */
594                 result = dateVal * (double) SECS_PER_DAY;
595 #endif
596         }
597
598         return result;
599 }
600
601 static TimestampTz
602 date2timestamptz(DateADT dateVal)
603 {
604         TimestampTz result;
605         struct pg_tm tt,
606                            *tm = &tt;
607         int                     tz;
608
609         if (DATE_IS_NOBEGIN(dateVal))
610                 TIMESTAMP_NOBEGIN(result);
611         else if (DATE_IS_NOEND(dateVal))
612                 TIMESTAMP_NOEND(result);
613         else
614         {
615                 /*
616                  * Date's range is wider than timestamp's, so check for boundaries.
617                  * Since dates have the same minimum values as timestamps, only upper
618                  * boundary need be checked for overflow.
619                  */
620                 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
621                         ereport(ERROR,
622                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
623                                          errmsg("date out of range for timestamp")));
624
625                 j2date(dateVal + POSTGRES_EPOCH_JDATE,
626                            &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
627                 tm->tm_hour = 0;
628                 tm->tm_min = 0;
629                 tm->tm_sec = 0;
630                 tz = DetermineTimeZoneOffset(tm, session_timezone);
631
632 #ifdef HAVE_INT64_TIMESTAMP
633                 result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
634 #else
635                 result = dateVal * (double) SECS_PER_DAY + tz;
636 #endif
637
638                 /*
639                  * Since it is possible to go beyond allowed timestamptz range because
640                  * of time zone, check for allowed timestamp range after adding tz.
641                  */
642                 if (!IS_VALID_TIMESTAMP(result))
643                         ereport(ERROR,
644                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
645                                          errmsg("date out of range for timestamp")));
646         }
647
648         return result;
649 }
650
651 /*
652  * date2timestamp_no_overflow
653  *
654  * This is chartered to produce a double value that is numerically
655  * equivalent to the corresponding Timestamp value, if the date is in the
656  * valid range of Timestamps, but in any case not throw an overflow error.
657  * We can do this since the numerical range of double is greater than
658  * that of non-erroneous timestamps.  The results are currently only
659  * used for statistical estimation purposes.
660  */
661 double
662 date2timestamp_no_overflow(DateADT dateVal)
663 {
664         double          result;
665
666         if (DATE_IS_NOBEGIN(dateVal))
667                 result = -DBL_MAX;
668         else if (DATE_IS_NOEND(dateVal))
669                 result = DBL_MAX;
670         else
671         {
672 #ifdef HAVE_INT64_TIMESTAMP
673                 /* date is days since 2000, timestamp is microseconds since same... */
674                 result = dateVal * (double) USECS_PER_DAY;
675 #else
676                 /* date is days since 2000, timestamp is seconds since same... */
677                 result = dateVal * (double) SECS_PER_DAY;
678 #endif
679         }
680
681         return result;
682 }
683
684
685 /*
686  * Crosstype comparison functions for dates
687  */
688
689 Datum
690 date_eq_timestamp(PG_FUNCTION_ARGS)
691 {
692         DateADT         dateVal = PG_GETARG_DATEADT(0);
693         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
694         Timestamp       dt1;
695
696         dt1 = date2timestamp(dateVal);
697
698         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
699 }
700
701 Datum
702 date_ne_timestamp(PG_FUNCTION_ARGS)
703 {
704         DateADT         dateVal = PG_GETARG_DATEADT(0);
705         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
706         Timestamp       dt1;
707
708         dt1 = date2timestamp(dateVal);
709
710         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
711 }
712
713 Datum
714 date_lt_timestamp(PG_FUNCTION_ARGS)
715 {
716         DateADT         dateVal = PG_GETARG_DATEADT(0);
717         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
718         Timestamp       dt1;
719
720         dt1 = date2timestamp(dateVal);
721
722         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
723 }
724
725 Datum
726 date_gt_timestamp(PG_FUNCTION_ARGS)
727 {
728         DateADT         dateVal = PG_GETARG_DATEADT(0);
729         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
730         Timestamp       dt1;
731
732         dt1 = date2timestamp(dateVal);
733
734         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
735 }
736
737 Datum
738 date_le_timestamp(PG_FUNCTION_ARGS)
739 {
740         DateADT         dateVal = PG_GETARG_DATEADT(0);
741         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
742         Timestamp       dt1;
743
744         dt1 = date2timestamp(dateVal);
745
746         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
747 }
748
749 Datum
750 date_ge_timestamp(PG_FUNCTION_ARGS)
751 {
752         DateADT         dateVal = PG_GETARG_DATEADT(0);
753         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
754         Timestamp       dt1;
755
756         dt1 = date2timestamp(dateVal);
757
758         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
759 }
760
761 Datum
762 date_cmp_timestamp(PG_FUNCTION_ARGS)
763 {
764         DateADT         dateVal = PG_GETARG_DATEADT(0);
765         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
766         Timestamp       dt1;
767
768         dt1 = date2timestamp(dateVal);
769
770         PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
771 }
772
773 Datum
774 date_eq_timestamptz(PG_FUNCTION_ARGS)
775 {
776         DateADT         dateVal = PG_GETARG_DATEADT(0);
777         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
778         TimestampTz dt1;
779
780         dt1 = date2timestamptz(dateVal);
781
782         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
783 }
784
785 Datum
786 date_ne_timestamptz(PG_FUNCTION_ARGS)
787 {
788         DateADT         dateVal = PG_GETARG_DATEADT(0);
789         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
790         TimestampTz dt1;
791
792         dt1 = date2timestamptz(dateVal);
793
794         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
795 }
796
797 Datum
798 date_lt_timestamptz(PG_FUNCTION_ARGS)
799 {
800         DateADT         dateVal = PG_GETARG_DATEADT(0);
801         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
802         TimestampTz dt1;
803
804         dt1 = date2timestamptz(dateVal);
805
806         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
807 }
808
809 Datum
810 date_gt_timestamptz(PG_FUNCTION_ARGS)
811 {
812         DateADT         dateVal = PG_GETARG_DATEADT(0);
813         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
814         TimestampTz dt1;
815
816         dt1 = date2timestamptz(dateVal);
817
818         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
819 }
820
821 Datum
822 date_le_timestamptz(PG_FUNCTION_ARGS)
823 {
824         DateADT         dateVal = PG_GETARG_DATEADT(0);
825         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
826         TimestampTz dt1;
827
828         dt1 = date2timestamptz(dateVal);
829
830         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
831 }
832
833 Datum
834 date_ge_timestamptz(PG_FUNCTION_ARGS)
835 {
836         DateADT         dateVal = PG_GETARG_DATEADT(0);
837         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
838         TimestampTz dt1;
839
840         dt1 = date2timestamptz(dateVal);
841
842         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
843 }
844
845 Datum
846 date_cmp_timestamptz(PG_FUNCTION_ARGS)
847 {
848         DateADT         dateVal = PG_GETARG_DATEADT(0);
849         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
850         TimestampTz dt1;
851
852         dt1 = date2timestamptz(dateVal);
853
854         PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
855 }
856
857 Datum
858 timestamp_eq_date(PG_FUNCTION_ARGS)
859 {
860         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
861         DateADT         dateVal = PG_GETARG_DATEADT(1);
862         Timestamp       dt2;
863
864         dt2 = date2timestamp(dateVal);
865
866         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
867 }
868
869 Datum
870 timestamp_ne_date(PG_FUNCTION_ARGS)
871 {
872         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
873         DateADT         dateVal = PG_GETARG_DATEADT(1);
874         Timestamp       dt2;
875
876         dt2 = date2timestamp(dateVal);
877
878         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
879 }
880
881 Datum
882 timestamp_lt_date(PG_FUNCTION_ARGS)
883 {
884         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
885         DateADT         dateVal = PG_GETARG_DATEADT(1);
886         Timestamp       dt2;
887
888         dt2 = date2timestamp(dateVal);
889
890         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
891 }
892
893 Datum
894 timestamp_gt_date(PG_FUNCTION_ARGS)
895 {
896         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
897         DateADT         dateVal = PG_GETARG_DATEADT(1);
898         Timestamp       dt2;
899
900         dt2 = date2timestamp(dateVal);
901
902         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
903 }
904
905 Datum
906 timestamp_le_date(PG_FUNCTION_ARGS)
907 {
908         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
909         DateADT         dateVal = PG_GETARG_DATEADT(1);
910         Timestamp       dt2;
911
912         dt2 = date2timestamp(dateVal);
913
914         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
915 }
916
917 Datum
918 timestamp_ge_date(PG_FUNCTION_ARGS)
919 {
920         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
921         DateADT         dateVal = PG_GETARG_DATEADT(1);
922         Timestamp       dt2;
923
924         dt2 = date2timestamp(dateVal);
925
926         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
927 }
928
929 Datum
930 timestamp_cmp_date(PG_FUNCTION_ARGS)
931 {
932         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
933         DateADT         dateVal = PG_GETARG_DATEADT(1);
934         Timestamp       dt2;
935
936         dt2 = date2timestamp(dateVal);
937
938         PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
939 }
940
941 Datum
942 timestamptz_eq_date(PG_FUNCTION_ARGS)
943 {
944         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
945         DateADT         dateVal = PG_GETARG_DATEADT(1);
946         TimestampTz dt2;
947
948         dt2 = date2timestamptz(dateVal);
949
950         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
951 }
952
953 Datum
954 timestamptz_ne_date(PG_FUNCTION_ARGS)
955 {
956         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
957         DateADT         dateVal = PG_GETARG_DATEADT(1);
958         TimestampTz dt2;
959
960         dt2 = date2timestamptz(dateVal);
961
962         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
963 }
964
965 Datum
966 timestamptz_lt_date(PG_FUNCTION_ARGS)
967 {
968         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
969         DateADT         dateVal = PG_GETARG_DATEADT(1);
970         TimestampTz dt2;
971
972         dt2 = date2timestamptz(dateVal);
973
974         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
975 }
976
977 Datum
978 timestamptz_gt_date(PG_FUNCTION_ARGS)
979 {
980         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
981         DateADT         dateVal = PG_GETARG_DATEADT(1);
982         TimestampTz dt2;
983
984         dt2 = date2timestamptz(dateVal);
985
986         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
987 }
988
989 Datum
990 timestamptz_le_date(PG_FUNCTION_ARGS)
991 {
992         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
993         DateADT         dateVal = PG_GETARG_DATEADT(1);
994         TimestampTz dt2;
995
996         dt2 = date2timestamptz(dateVal);
997
998         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
999 }
1000
1001 Datum
1002 timestamptz_ge_date(PG_FUNCTION_ARGS)
1003 {
1004         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1005         DateADT         dateVal = PG_GETARG_DATEADT(1);
1006         TimestampTz dt2;
1007
1008         dt2 = date2timestamptz(dateVal);
1009
1010         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
1011 }
1012
1013 Datum
1014 timestamptz_cmp_date(PG_FUNCTION_ARGS)
1015 {
1016         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1017         DateADT         dateVal = PG_GETARG_DATEADT(1);
1018         TimestampTz dt2;
1019
1020         dt2 = date2timestamptz(dateVal);
1021
1022         PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
1023 }
1024
1025
1026 /* Add an interval to a date, giving a new date.
1027  * Must handle both positive and negative intervals.
1028  *
1029  * We implement this by promoting the date to timestamp (without time zone)
1030  * and then using the timestamp plus interval function.
1031  */
1032 Datum
1033 date_pl_interval(PG_FUNCTION_ARGS)
1034 {
1035         DateADT         dateVal = PG_GETARG_DATEADT(0);
1036         Interval   *span = PG_GETARG_INTERVAL_P(1);
1037         Timestamp       dateStamp;
1038
1039         dateStamp = date2timestamp(dateVal);
1040
1041         return DirectFunctionCall2(timestamp_pl_interval,
1042                                                            TimestampGetDatum(dateStamp),
1043                                                            PointerGetDatum(span));
1044 }
1045
1046 /* Subtract an interval from a date, giving a new date.
1047  * Must handle both positive and negative intervals.
1048  *
1049  * We implement this by promoting the date to timestamp (without time zone)
1050  * and then using the timestamp minus interval function.
1051  */
1052 Datum
1053 date_mi_interval(PG_FUNCTION_ARGS)
1054 {
1055         DateADT         dateVal = PG_GETARG_DATEADT(0);
1056         Interval   *span = PG_GETARG_INTERVAL_P(1);
1057         Timestamp       dateStamp;
1058
1059         dateStamp = date2timestamp(dateVal);
1060
1061         return DirectFunctionCall2(timestamp_mi_interval,
1062                                                            TimestampGetDatum(dateStamp),
1063                                                            PointerGetDatum(span));
1064 }
1065
1066 /* date_timestamp()
1067  * Convert date to timestamp data type.
1068  */
1069 Datum
1070 date_timestamp(PG_FUNCTION_ARGS)
1071 {
1072         DateADT         dateVal = PG_GETARG_DATEADT(0);
1073         Timestamp       result;
1074
1075         result = date2timestamp(dateVal);
1076
1077         PG_RETURN_TIMESTAMP(result);
1078 }
1079
1080 /* timestamp_date()
1081  * Convert timestamp to date data type.
1082  */
1083 Datum
1084 timestamp_date(PG_FUNCTION_ARGS)
1085 {
1086         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
1087         DateADT         result;
1088         struct pg_tm tt,
1089                            *tm = &tt;
1090         fsec_t          fsec;
1091
1092         if (TIMESTAMP_IS_NOBEGIN(timestamp))
1093                 DATE_NOBEGIN(result);
1094         else if (TIMESTAMP_IS_NOEND(timestamp))
1095                 DATE_NOEND(result);
1096         else
1097         {
1098                 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1099                         ereport(ERROR,
1100                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1101                                          errmsg("timestamp out of range")));
1102
1103                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1104         }
1105
1106         PG_RETURN_DATEADT(result);
1107 }
1108
1109
1110 /* date_timestamptz()
1111  * Convert date to timestamp with time zone data type.
1112  */
1113 Datum
1114 date_timestamptz(PG_FUNCTION_ARGS)
1115 {
1116         DateADT         dateVal = PG_GETARG_DATEADT(0);
1117         TimestampTz result;
1118
1119         result = date2timestamptz(dateVal);
1120
1121         PG_RETURN_TIMESTAMP(result);
1122 }
1123
1124
1125 /* timestamptz_date()
1126  * Convert timestamp with time zone to date data type.
1127  */
1128 Datum
1129 timestamptz_date(PG_FUNCTION_ARGS)
1130 {
1131         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1132         DateADT         result;
1133         struct pg_tm tt,
1134                            *tm = &tt;
1135         fsec_t          fsec;
1136         int                     tz;
1137
1138         if (TIMESTAMP_IS_NOBEGIN(timestamp))
1139                 DATE_NOBEGIN(result);
1140         else if (TIMESTAMP_IS_NOEND(timestamp))
1141                 DATE_NOEND(result);
1142         else
1143         {
1144                 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1145                         ereport(ERROR,
1146                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1147                                          errmsg("timestamp out of range")));
1148
1149                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1150         }
1151
1152         PG_RETURN_DATEADT(result);
1153 }
1154
1155
1156 /* abstime_date()
1157  * Convert abstime to date data type.
1158  */
1159 Datum
1160 abstime_date(PG_FUNCTION_ARGS)
1161 {
1162         AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
1163         DateADT         result;
1164         struct pg_tm tt,
1165                            *tm = &tt;
1166         int                     tz;
1167
1168         switch (abstime)
1169         {
1170                 case INVALID_ABSTIME:
1171                         ereport(ERROR,
1172                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1173                                    errmsg("cannot convert reserved abstime value to date")));
1174                         result = 0;                     /* keep compiler quiet */
1175                         break;
1176
1177                 case NOSTART_ABSTIME:
1178                         DATE_NOBEGIN(result);
1179                         break;
1180
1181                 case NOEND_ABSTIME:
1182                         DATE_NOEND(result);
1183                         break;
1184
1185                 default:
1186                         abstime2tm(abstime, &tz, tm, NULL);
1187                         /* Prevent overflow in Julian-day routines */
1188                         if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1189                                 ereport(ERROR,
1190                                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1191                                                  errmsg("abstime out of range for date")));
1192                         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1193                         /* Now check for just-out-of-range dates */
1194                         if (!IS_VALID_DATE(result))
1195                                 ereport(ERROR,
1196                                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1197                                                  errmsg("abstime out of range for date")));
1198                         break;
1199         }
1200
1201         PG_RETURN_DATEADT(result);
1202 }
1203
1204
1205 /*****************************************************************************
1206  *       Time ADT
1207  *****************************************************************************/
1208
1209 Datum
1210 time_in(PG_FUNCTION_ARGS)
1211 {
1212         char       *str = PG_GETARG_CSTRING(0);
1213
1214 #ifdef NOT_USED
1215         Oid                     typelem = PG_GETARG_OID(1);
1216 #endif
1217         int32           typmod = PG_GETARG_INT32(2);
1218         TimeADT         result;
1219         fsec_t          fsec;
1220         struct pg_tm tt,
1221                            *tm = &tt;
1222         int                     tz;
1223         int                     nf;
1224         int                     dterr;
1225         char            workbuf[MAXDATELEN + 1];
1226         char       *field[MAXDATEFIELDS];
1227         int                     dtype;
1228         int                     ftype[MAXDATEFIELDS];
1229
1230         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1231                                                   field, ftype, MAXDATEFIELDS, &nf);
1232         if (dterr == 0)
1233                 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
1234         if (dterr != 0)
1235                 DateTimeParseError(dterr, str, "time");
1236
1237         tm2time(tm, fsec, &result);
1238         AdjustTimeForTypmod(&result, typmod);
1239
1240         PG_RETURN_TIMEADT(result);
1241 }
1242
1243 /* tm2time()
1244  * Convert a tm structure to a time data type.
1245  */
1246 static int
1247 tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
1248 {
1249 #ifdef HAVE_INT64_TIMESTAMP
1250         *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
1251                            * USECS_PER_SEC) + fsec;
1252 #else
1253         *result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1254 #endif
1255         return 0;
1256 }
1257
1258 /* time2tm()
1259  * Convert time data type to POSIX time structure.
1260  *
1261  * For dates within the range of pg_time_t, convert to the local time zone.
1262  * If out of this range, leave as UTC (in practice that could only happen
1263  * if pg_time_t is just 32 bits) - thomas 97/05/27
1264  */
1265 static int
1266 time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
1267 {
1268 #ifdef HAVE_INT64_TIMESTAMP
1269         tm->tm_hour = time / USECS_PER_HOUR;
1270         time -= tm->tm_hour * USECS_PER_HOUR;
1271         tm->tm_min = time / USECS_PER_MINUTE;
1272         time -= tm->tm_min * USECS_PER_MINUTE;
1273         tm->tm_sec = time / USECS_PER_SEC;
1274         time -= tm->tm_sec * USECS_PER_SEC;
1275         *fsec = time;
1276 #else
1277         double          trem;
1278
1279 recalc:
1280         trem = time;
1281         TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
1282         TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
1283         TMODULO(trem, tm->tm_sec, 1.0);
1284         trem = TIMEROUND(trem);
1285         /* roundoff may need to propagate to higher-order fields */
1286         if (trem >= 1.0)
1287         {
1288                 time = ceil(time);
1289                 goto recalc;
1290         }
1291         *fsec = trem;
1292 #endif
1293
1294         return 0;
1295 }
1296
1297 Datum
1298 time_out(PG_FUNCTION_ARGS)
1299 {
1300         TimeADT         time = PG_GETARG_TIMEADT(0);
1301         char       *result;
1302         struct pg_tm tt,
1303                            *tm = &tt;
1304         fsec_t          fsec;
1305         char            buf[MAXDATELEN + 1];
1306
1307         time2tm(time, tm, &fsec);
1308         EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
1309
1310         result = pstrdup(buf);
1311         PG_RETURN_CSTRING(result);
1312 }
1313
1314 /*
1315  *              time_recv                       - converts external binary format to time
1316  *
1317  * We make no attempt to provide compatibility between int and float
1318  * time representations ...
1319  */
1320 Datum
1321 time_recv(PG_FUNCTION_ARGS)
1322 {
1323         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
1324
1325 #ifdef NOT_USED
1326         Oid                     typelem = PG_GETARG_OID(1);
1327 #endif
1328         int32           typmod = PG_GETARG_INT32(2);
1329         TimeADT         result;
1330
1331 #ifdef HAVE_INT64_TIMESTAMP
1332         result = pq_getmsgint64(buf);
1333
1334         if (result < INT64CONST(0) || result > USECS_PER_DAY)
1335                 ereport(ERROR,
1336                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1337                                  errmsg("time out of range")));
1338 #else
1339         result = pq_getmsgfloat8(buf);
1340
1341         if (result < 0 || result > (double) SECS_PER_DAY)
1342                 ereport(ERROR,
1343                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1344                                  errmsg("time out of range")));
1345 #endif
1346
1347         AdjustTimeForTypmod(&result, typmod);
1348
1349         PG_RETURN_TIMEADT(result);
1350 }
1351
1352 /*
1353  *              time_send                       - converts time to binary format
1354  */
1355 Datum
1356 time_send(PG_FUNCTION_ARGS)
1357 {
1358         TimeADT         time = PG_GETARG_TIMEADT(0);
1359         StringInfoData buf;
1360
1361         pq_begintypsend(&buf);
1362 #ifdef HAVE_INT64_TIMESTAMP
1363         pq_sendint64(&buf, time);
1364 #else
1365         pq_sendfloat8(&buf, time);
1366 #endif
1367         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1368 }
1369
1370 Datum
1371 timetypmodin(PG_FUNCTION_ARGS)
1372 {
1373         ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
1374
1375         PG_RETURN_INT32(anytime_typmodin(false, ta));
1376 }
1377
1378 Datum
1379 timetypmodout(PG_FUNCTION_ARGS)
1380 {
1381         int32           typmod = PG_GETARG_INT32(0);
1382
1383         PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1384 }
1385
1386 /*
1387  *              make_time                       - time constructor
1388  */
1389 Datum
1390 make_time(PG_FUNCTION_ARGS)
1391 {
1392         int                     tm_hour = PG_GETARG_INT32(0);
1393         int                     tm_min = PG_GETARG_INT32(1);
1394         double          sec = PG_GETARG_FLOAT8(2);
1395         TimeADT         time;
1396
1397         /* This should match the checks in DecodeTimeOnly */
1398         if (tm_hour < 0 || tm_min < 0 || tm_min > MINS_PER_HOUR - 1 ||
1399                 sec < 0 || sec > SECS_PER_MINUTE ||
1400                 tm_hour > HOURS_PER_DAY ||
1401         /* test for > 24:00:00 */
1402                 (tm_hour == HOURS_PER_DAY && (tm_min > 0 || sec > 0)))
1403                 ereport(ERROR,
1404                                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
1405                                  errmsg("time field value out of range: %d:%02d:%02g",
1406                                                 tm_hour, tm_min, sec)));
1407
1408         /* This should match tm2time */
1409 #ifdef HAVE_INT64_TIMESTAMP
1410         time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
1411                         * USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
1412 #else
1413         time = ((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE) + sec;
1414 #endif
1415
1416         PG_RETURN_TIMEADT(time);
1417 }
1418
1419
1420 /* time_transform()
1421  * Flatten calls to time_scale() and timetz_scale() that solely represent
1422  * increases in allowed precision.
1423  */
1424 Datum
1425 time_transform(PG_FUNCTION_ARGS)
1426 {
1427         PG_RETURN_POINTER(TemporalTransform(MAX_TIME_PRECISION,
1428                                                                                 (Node *) PG_GETARG_POINTER(0)));
1429 }
1430
1431 /* time_scale()
1432  * Adjust time type for specified scale factor.
1433  * Used by PostgreSQL type system to stuff columns.
1434  */
1435 Datum
1436 time_scale(PG_FUNCTION_ARGS)
1437 {
1438         TimeADT         time = PG_GETARG_TIMEADT(0);
1439         int32           typmod = PG_GETARG_INT32(1);
1440         TimeADT         result;
1441
1442         result = time;
1443         AdjustTimeForTypmod(&result, typmod);
1444
1445         PG_RETURN_TIMEADT(result);
1446 }
1447
1448 /* AdjustTimeForTypmod()
1449  * Force the precision of the time value to a specified value.
1450  * Uses *exactly* the same code as in AdjustTimestampForTypemod()
1451  * but we make a separate copy because those types do not
1452  * have a fundamental tie together but rather a coincidence of
1453  * implementation. - thomas
1454  */
1455 static void
1456 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1457 {
1458 #ifdef HAVE_INT64_TIMESTAMP
1459         static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1460                 INT64CONST(1000000),
1461                 INT64CONST(100000),
1462                 INT64CONST(10000),
1463                 INT64CONST(1000),
1464                 INT64CONST(100),
1465                 INT64CONST(10),
1466                 INT64CONST(1)
1467         };
1468
1469         static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1470                 INT64CONST(500000),
1471                 INT64CONST(50000),
1472                 INT64CONST(5000),
1473                 INT64CONST(500),
1474                 INT64CONST(50),
1475                 INT64CONST(5),
1476                 INT64CONST(0)
1477         };
1478 #else
1479         /* note MAX_TIME_PRECISION differs in this case */
1480         static const double TimeScales[MAX_TIME_PRECISION + 1] = {
1481                 1.0,
1482                 10.0,
1483                 100.0,
1484                 1000.0,
1485                 10000.0,
1486                 100000.0,
1487                 1000000.0,
1488                 10000000.0,
1489                 100000000.0,
1490                 1000000000.0,
1491                 10000000000.0
1492         };
1493 #endif
1494
1495         if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1496         {
1497                 /*
1498                  * Note: this round-to-nearest code is not completely consistent about
1499                  * rounding values that are exactly halfway between integral values.
1500                  * On most platforms, rint() will implement round-to-nearest-even, but
1501                  * the integer code always rounds up (away from zero).  Is it worth
1502                  * trying to be consistent?
1503                  */
1504 #ifdef HAVE_INT64_TIMESTAMP
1505                 if (*time >= INT64CONST(0))
1506                         *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
1507                                 TimeScales[typmod];
1508                 else
1509                         *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
1510                                           TimeScales[typmod]);
1511 #else
1512                 *time = rint((double) *time * TimeScales[typmod]) / TimeScales[typmod];
1513 #endif
1514         }
1515 }
1516
1517
1518 Datum
1519 time_eq(PG_FUNCTION_ARGS)
1520 {
1521         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1522         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1523
1524         PG_RETURN_BOOL(time1 == time2);
1525 }
1526
1527 Datum
1528 time_ne(PG_FUNCTION_ARGS)
1529 {
1530         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1531         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1532
1533         PG_RETURN_BOOL(time1 != time2);
1534 }
1535
1536 Datum
1537 time_lt(PG_FUNCTION_ARGS)
1538 {
1539         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1540         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1541
1542         PG_RETURN_BOOL(time1 < time2);
1543 }
1544
1545 Datum
1546 time_le(PG_FUNCTION_ARGS)
1547 {
1548         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1549         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1550
1551         PG_RETURN_BOOL(time1 <= time2);
1552 }
1553
1554 Datum
1555 time_gt(PG_FUNCTION_ARGS)
1556 {
1557         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1558         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1559
1560         PG_RETURN_BOOL(time1 > time2);
1561 }
1562
1563 Datum
1564 time_ge(PG_FUNCTION_ARGS)
1565 {
1566         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1567         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1568
1569         PG_RETURN_BOOL(time1 >= time2);
1570 }
1571
1572 Datum
1573 time_cmp(PG_FUNCTION_ARGS)
1574 {
1575         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1576         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1577
1578         if (time1 < time2)
1579                 PG_RETURN_INT32(-1);
1580         if (time1 > time2)
1581                 PG_RETURN_INT32(1);
1582         PG_RETURN_INT32(0);
1583 }
1584
1585 Datum
1586 time_hash(PG_FUNCTION_ARGS)
1587 {
1588         /* We can use either hashint8 or hashfloat8 directly */
1589 #ifdef HAVE_INT64_TIMESTAMP
1590         return hashint8(fcinfo);
1591 #else
1592         return hashfloat8(fcinfo);
1593 #endif
1594 }
1595
1596 Datum
1597 time_larger(PG_FUNCTION_ARGS)
1598 {
1599         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1600         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1601
1602         PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1603 }
1604
1605 Datum
1606 time_smaller(PG_FUNCTION_ARGS)
1607 {
1608         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1609         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1610
1611         PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1612 }
1613
1614 /* overlaps_time() --- implements the SQL OVERLAPS operator.
1615  *
1616  * Algorithm is per SQL spec.  This is much harder than you'd think
1617  * because the spec requires us to deliver a non-null answer in some cases
1618  * where some of the inputs are null.
1619  */
1620 Datum
1621 overlaps_time(PG_FUNCTION_ARGS)
1622 {
1623         /*
1624          * The arguments are TimeADT, but we leave them as generic Datums to avoid
1625          * dereferencing nulls (TimeADT is pass-by-reference!)
1626          */
1627         Datum           ts1 = PG_GETARG_DATUM(0);
1628         Datum           te1 = PG_GETARG_DATUM(1);
1629         Datum           ts2 = PG_GETARG_DATUM(2);
1630         Datum           te2 = PG_GETARG_DATUM(3);
1631         bool            ts1IsNull = PG_ARGISNULL(0);
1632         bool            te1IsNull = PG_ARGISNULL(1);
1633         bool            ts2IsNull = PG_ARGISNULL(2);
1634         bool            te2IsNull = PG_ARGISNULL(3);
1635
1636 #define TIMEADT_GT(t1,t2) \
1637         (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1638 #define TIMEADT_LT(t1,t2) \
1639         (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1640
1641         /*
1642          * If both endpoints of interval 1 are null, the result is null (unknown).
1643          * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1644          * take ts1 as the lesser endpoint.
1645          */
1646         if (ts1IsNull)
1647         {
1648                 if (te1IsNull)
1649                         PG_RETURN_NULL();
1650                 /* swap null for non-null */
1651                 ts1 = te1;
1652                 te1IsNull = true;
1653         }
1654         else if (!te1IsNull)
1655         {
1656                 if (TIMEADT_GT(ts1, te1))
1657                 {
1658                         Datum           tt = ts1;
1659
1660                         ts1 = te1;
1661                         te1 = tt;
1662                 }
1663         }
1664
1665         /* Likewise for interval 2. */
1666         if (ts2IsNull)
1667         {
1668                 if (te2IsNull)
1669                         PG_RETURN_NULL();
1670                 /* swap null for non-null */
1671                 ts2 = te2;
1672                 te2IsNull = true;
1673         }
1674         else if (!te2IsNull)
1675         {
1676                 if (TIMEADT_GT(ts2, te2))
1677                 {
1678                         Datum           tt = ts2;
1679
1680                         ts2 = te2;
1681                         te2 = tt;
1682                 }
1683         }
1684
1685         /*
1686          * At this point neither ts1 nor ts2 is null, so we can consider three
1687          * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1688          */
1689         if (TIMEADT_GT(ts1, ts2))
1690         {
1691                 /*
1692                  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1693                  * in the presence of nulls it's not quite completely so.
1694                  */
1695                 if (te2IsNull)
1696                         PG_RETURN_NULL();
1697                 if (TIMEADT_LT(ts1, te2))
1698                         PG_RETURN_BOOL(true);
1699                 if (te1IsNull)
1700                         PG_RETURN_NULL();
1701
1702                 /*
1703                  * If te1 is not null then we had ts1 <= te1 above, and we just found
1704                  * ts1 >= te2, hence te1 >= te2.
1705                  */
1706                 PG_RETURN_BOOL(false);
1707         }
1708         else if (TIMEADT_LT(ts1, ts2))
1709         {
1710                 /* This case is ts2 < te1 OR te2 < te1 */
1711                 if (te1IsNull)
1712                         PG_RETURN_NULL();
1713                 if (TIMEADT_LT(ts2, te1))
1714                         PG_RETURN_BOOL(true);
1715                 if (te2IsNull)
1716                         PG_RETURN_NULL();
1717
1718                 /*
1719                  * If te2 is not null then we had ts2 <= te2 above, and we just found
1720                  * ts2 >= te1, hence te2 >= te1.
1721                  */
1722                 PG_RETURN_BOOL(false);
1723         }
1724         else
1725         {
1726                 /*
1727                  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1728                  * rather silly way of saying "true if both are nonnull, else null".
1729                  */
1730                 if (te1IsNull || te2IsNull)
1731                         PG_RETURN_NULL();
1732                 PG_RETURN_BOOL(true);
1733         }
1734
1735 #undef TIMEADT_GT
1736 #undef TIMEADT_LT
1737 }
1738
1739 /* timestamp_time()
1740  * Convert timestamp to time data type.
1741  */
1742 Datum
1743 timestamp_time(PG_FUNCTION_ARGS)
1744 {
1745         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
1746         TimeADT         result;
1747         struct pg_tm tt,
1748                            *tm = &tt;
1749         fsec_t          fsec;
1750
1751         if (TIMESTAMP_NOT_FINITE(timestamp))
1752                 PG_RETURN_NULL();
1753
1754         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1755                 ereport(ERROR,
1756                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1757                                  errmsg("timestamp out of range")));
1758
1759 #ifdef HAVE_INT64_TIMESTAMP
1760
1761         /*
1762          * Could also do this with time = (timestamp / USECS_PER_DAY *
1763          * USECS_PER_DAY) - timestamp;
1764          */
1765         result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1766                           USECS_PER_SEC) + fsec;
1767 #else
1768         result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1769 #endif
1770
1771         PG_RETURN_TIMEADT(result);
1772 }
1773
1774 /* timestamptz_time()
1775  * Convert timestamptz to time data type.
1776  */
1777 Datum
1778 timestamptz_time(PG_FUNCTION_ARGS)
1779 {
1780         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1781         TimeADT         result;
1782         struct pg_tm tt,
1783                            *tm = &tt;
1784         int                     tz;
1785         fsec_t          fsec;
1786
1787         if (TIMESTAMP_NOT_FINITE(timestamp))
1788                 PG_RETURN_NULL();
1789
1790         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1791                 ereport(ERROR,
1792                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1793                                  errmsg("timestamp out of range")));
1794
1795 #ifdef HAVE_INT64_TIMESTAMP
1796
1797         /*
1798          * Could also do this with time = (timestamp / USECS_PER_DAY *
1799          * USECS_PER_DAY) - timestamp;
1800          */
1801         result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1802                           USECS_PER_SEC) + fsec;
1803 #else
1804         result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1805 #endif
1806
1807         PG_RETURN_TIMEADT(result);
1808 }
1809
1810 /* datetime_timestamp()
1811  * Convert date and time to timestamp data type.
1812  */
1813 Datum
1814 datetime_timestamp(PG_FUNCTION_ARGS)
1815 {
1816         DateADT         date = PG_GETARG_DATEADT(0);
1817         TimeADT         time = PG_GETARG_TIMEADT(1);
1818         Timestamp       result;
1819
1820         result = date2timestamp(date);
1821         if (!TIMESTAMP_NOT_FINITE(result))
1822         {
1823                 result += time;
1824                 if (!IS_VALID_TIMESTAMP(result))
1825                         ereport(ERROR,
1826                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1827                                          errmsg("timestamp out of range")));
1828         }
1829
1830         PG_RETURN_TIMESTAMP(result);
1831 }
1832
1833 /* time_interval()
1834  * Convert time to interval data type.
1835  */
1836 Datum
1837 time_interval(PG_FUNCTION_ARGS)
1838 {
1839         TimeADT         time = PG_GETARG_TIMEADT(0);
1840         Interval   *result;
1841
1842         result = (Interval *) palloc(sizeof(Interval));
1843
1844         result->time = time;
1845         result->day = 0;
1846         result->month = 0;
1847
1848         PG_RETURN_INTERVAL_P(result);
1849 }
1850
1851 /* interval_time()
1852  * Convert interval to time data type.
1853  *
1854  * This is defined as producing the fractional-day portion of the interval.
1855  * Therefore, we can just ignore the months field.  It is not real clear
1856  * what to do with negative intervals, but we choose to subtract the floor,
1857  * so that, say, '-2 hours' becomes '22:00:00'.
1858  */
1859 Datum
1860 interval_time(PG_FUNCTION_ARGS)
1861 {
1862         Interval   *span = PG_GETARG_INTERVAL_P(0);
1863         TimeADT         result;
1864
1865 #ifdef HAVE_INT64_TIMESTAMP
1866         int64           days;
1867
1868         result = span->time;
1869         if (result >= USECS_PER_DAY)
1870         {
1871                 days = result / USECS_PER_DAY;
1872                 result -= days * USECS_PER_DAY;
1873         }
1874         else if (result < 0)
1875         {
1876                 days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
1877                 result += days * USECS_PER_DAY;
1878         }
1879 #else
1880         result = span->time;
1881         if (result >= (double) SECS_PER_DAY || result < 0)
1882                 result -= floor(result / (double) SECS_PER_DAY) * (double) SECS_PER_DAY;
1883 #endif
1884
1885         PG_RETURN_TIMEADT(result);
1886 }
1887
1888 /* time_mi_time()
1889  * Subtract two times to produce an interval.
1890  */
1891 Datum
1892 time_mi_time(PG_FUNCTION_ARGS)
1893 {
1894         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1895         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1896         Interval   *result;
1897
1898         result = (Interval *) palloc(sizeof(Interval));
1899
1900         result->month = 0;
1901         result->day = 0;
1902         result->time = time1 - time2;
1903
1904         PG_RETURN_INTERVAL_P(result);
1905 }
1906
1907 /* time_pl_interval()
1908  * Add interval to time.
1909  */
1910 Datum
1911 time_pl_interval(PG_FUNCTION_ARGS)
1912 {
1913         TimeADT         time = PG_GETARG_TIMEADT(0);
1914         Interval   *span = PG_GETARG_INTERVAL_P(1);
1915         TimeADT         result;
1916
1917 #ifdef HAVE_INT64_TIMESTAMP
1918         result = time + span->time;
1919         result -= result / USECS_PER_DAY * USECS_PER_DAY;
1920         if (result < INT64CONST(0))
1921                 result += USECS_PER_DAY;
1922 #else
1923         TimeADT         time1;
1924
1925         result = time + span->time;
1926         TMODULO(result, time1, (double) SECS_PER_DAY);
1927         if (result < 0)
1928                 result += SECS_PER_DAY;
1929 #endif
1930
1931         PG_RETURN_TIMEADT(result);
1932 }
1933
1934 /* time_mi_interval()
1935  * Subtract interval from time.
1936  */
1937 Datum
1938 time_mi_interval(PG_FUNCTION_ARGS)
1939 {
1940         TimeADT         time = PG_GETARG_TIMEADT(0);
1941         Interval   *span = PG_GETARG_INTERVAL_P(1);
1942         TimeADT         result;
1943
1944 #ifdef HAVE_INT64_TIMESTAMP
1945         result = time - span->time;
1946         result -= result / USECS_PER_DAY * USECS_PER_DAY;
1947         if (result < INT64CONST(0))
1948                 result += USECS_PER_DAY;
1949 #else
1950         TimeADT         time1;
1951
1952         result = time - span->time;
1953         TMODULO(result, time1, (double) SECS_PER_DAY);
1954         if (result < 0)
1955                 result += SECS_PER_DAY;
1956 #endif
1957
1958         PG_RETURN_TIMEADT(result);
1959 }
1960
1961
1962 /* time_part()
1963  * Extract specified field from time type.
1964  */
1965 Datum
1966 time_part(PG_FUNCTION_ARGS)
1967 {
1968         text       *units = PG_GETARG_TEXT_PP(0);
1969         TimeADT         time = PG_GETARG_TIMEADT(1);
1970         float8          result;
1971         int                     type,
1972                                 val;
1973         char       *lowunits;
1974
1975         lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1976                                                                                         VARSIZE_ANY_EXHDR(units),
1977                                                                                         false);
1978
1979         type = DecodeUnits(0, lowunits, &val);
1980         if (type == UNKNOWN_FIELD)
1981                 type = DecodeSpecial(0, lowunits, &val);
1982
1983         if (type == UNITS)
1984         {
1985                 fsec_t          fsec;
1986                 struct pg_tm tt,
1987                                    *tm = &tt;
1988
1989                 time2tm(time, tm, &fsec);
1990
1991                 switch (val)
1992                 {
1993                         case DTK_MICROSEC:
1994 #ifdef HAVE_INT64_TIMESTAMP
1995                                 result = tm->tm_sec * 1000000.0 + fsec;
1996 #else
1997                                 result = (tm->tm_sec + fsec) * 1000000;
1998 #endif
1999                                 break;
2000
2001                         case DTK_MILLISEC:
2002 #ifdef HAVE_INT64_TIMESTAMP
2003                                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
2004 #else
2005                                 result = (tm->tm_sec + fsec) * 1000;
2006 #endif
2007                                 break;
2008
2009                         case DTK_SECOND:
2010 #ifdef HAVE_INT64_TIMESTAMP
2011                                 result = tm->tm_sec + fsec / 1000000.0;
2012 #else
2013                                 result = tm->tm_sec + fsec;
2014 #endif
2015                                 break;
2016
2017                         case DTK_MINUTE:
2018                                 result = tm->tm_min;
2019                                 break;
2020
2021                         case DTK_HOUR:
2022                                 result = tm->tm_hour;
2023                                 break;
2024
2025                         case DTK_TZ:
2026                         case DTK_TZ_MINUTE:
2027                         case DTK_TZ_HOUR:
2028                         case DTK_DAY:
2029                         case DTK_MONTH:
2030                         case DTK_QUARTER:
2031                         case DTK_YEAR:
2032                         case DTK_DECADE:
2033                         case DTK_CENTURY:
2034                         case DTK_MILLENNIUM:
2035                         case DTK_ISOYEAR:
2036                         default:
2037                                 ereport(ERROR,
2038                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2039                                                  errmsg("\"time\" units \"%s\" not recognized",
2040                                                                 lowunits)));
2041                                 result = 0;
2042                 }
2043         }
2044         else if (type == RESERV && val == DTK_EPOCH)
2045         {
2046 #ifdef HAVE_INT64_TIMESTAMP
2047                 result = time / 1000000.0;
2048 #else
2049                 result = time;
2050 #endif
2051         }
2052         else
2053         {
2054                 ereport(ERROR,
2055                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2056                                  errmsg("\"time\" units \"%s\" not recognized",
2057                                                 lowunits)));
2058                 result = 0;
2059         }
2060
2061         PG_RETURN_FLOAT8(result);
2062 }
2063
2064
2065 /*****************************************************************************
2066  *       Time With Time Zone ADT
2067  *****************************************************************************/
2068
2069 /* tm2timetz()
2070  * Convert a tm structure to a time data type.
2071  */
2072 static int
2073 tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
2074 {
2075 #ifdef HAVE_INT64_TIMESTAMP
2076         result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
2077                                         USECS_PER_SEC) + fsec;
2078 #else
2079         result->time = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
2080 #endif
2081         result->zone = tz;
2082
2083         return 0;
2084 }
2085
2086 Datum
2087 timetz_in(PG_FUNCTION_ARGS)
2088 {
2089         char       *str = PG_GETARG_CSTRING(0);
2090
2091 #ifdef NOT_USED
2092         Oid                     typelem = PG_GETARG_OID(1);
2093 #endif
2094         int32           typmod = PG_GETARG_INT32(2);
2095         TimeTzADT  *result;
2096         fsec_t          fsec;
2097         struct pg_tm tt,
2098                            *tm = &tt;
2099         int                     tz;
2100         int                     nf;
2101         int                     dterr;
2102         char            workbuf[MAXDATELEN + 1];
2103         char       *field[MAXDATEFIELDS];
2104         int                     dtype;
2105         int                     ftype[MAXDATEFIELDS];
2106
2107         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
2108                                                   field, ftype, MAXDATEFIELDS, &nf);
2109         if (dterr == 0)
2110                 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
2111         if (dterr != 0)
2112                 DateTimeParseError(dterr, str, "time with time zone");
2113
2114         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2115         tm2timetz(tm, fsec, tz, result);
2116         AdjustTimeForTypmod(&(result->time), typmod);
2117
2118         PG_RETURN_TIMETZADT_P(result);
2119 }
2120
2121 Datum
2122 timetz_out(PG_FUNCTION_ARGS)
2123 {
2124         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2125         char       *result;
2126         struct pg_tm tt,
2127                            *tm = &tt;
2128         fsec_t          fsec;
2129         int                     tz;
2130         char            buf[MAXDATELEN + 1];
2131
2132         timetz2tm(time, tm, &fsec, &tz);
2133         EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
2134
2135         result = pstrdup(buf);
2136         PG_RETURN_CSTRING(result);
2137 }
2138
2139 /*
2140  *              timetz_recv                     - converts external binary format to timetz
2141  */
2142 Datum
2143 timetz_recv(PG_FUNCTION_ARGS)
2144 {
2145         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
2146
2147 #ifdef NOT_USED
2148         Oid                     typelem = PG_GETARG_OID(1);
2149 #endif
2150         int32           typmod = PG_GETARG_INT32(2);
2151         TimeTzADT  *result;
2152
2153         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2154
2155 #ifdef HAVE_INT64_TIMESTAMP
2156         result->time = pq_getmsgint64(buf);
2157
2158         if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
2159                 ereport(ERROR,
2160                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2161                                  errmsg("time out of range")));
2162 #else
2163         result->time = pq_getmsgfloat8(buf);
2164
2165         if (result->time < 0 || result->time > (double) SECS_PER_DAY)
2166                 ereport(ERROR,
2167                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2168                                  errmsg("time out of range")));
2169 #endif
2170
2171         result->zone = pq_getmsgint(buf, sizeof(result->zone));
2172
2173         /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
2174         if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
2175                 ereport(ERROR,
2176                                 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
2177                                  errmsg("time zone displacement out of range")));
2178
2179         AdjustTimeForTypmod(&(result->time), typmod);
2180
2181         PG_RETURN_TIMETZADT_P(result);
2182 }
2183
2184 /*
2185  *              timetz_send                     - converts timetz to binary format
2186  */
2187 Datum
2188 timetz_send(PG_FUNCTION_ARGS)
2189 {
2190         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2191         StringInfoData buf;
2192
2193         pq_begintypsend(&buf);
2194 #ifdef HAVE_INT64_TIMESTAMP
2195         pq_sendint64(&buf, time->time);
2196 #else
2197         pq_sendfloat8(&buf, time->time);
2198 #endif
2199         pq_sendint(&buf, time->zone, sizeof(time->zone));
2200         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2201 }
2202
2203 Datum
2204 timetztypmodin(PG_FUNCTION_ARGS)
2205 {
2206         ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
2207
2208         PG_RETURN_INT32(anytime_typmodin(true, ta));
2209 }
2210
2211 Datum
2212 timetztypmodout(PG_FUNCTION_ARGS)
2213 {
2214         int32           typmod = PG_GETARG_INT32(0);
2215
2216         PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
2217 }
2218
2219
2220 /* timetz2tm()
2221  * Convert TIME WITH TIME ZONE data type to POSIX time structure.
2222  */
2223 static int
2224 timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp)
2225 {
2226         TimeOffset      trem = time->time;
2227
2228 #ifdef HAVE_INT64_TIMESTAMP
2229         tm->tm_hour = trem / USECS_PER_HOUR;
2230         trem -= tm->tm_hour * USECS_PER_HOUR;
2231         tm->tm_min = trem / USECS_PER_MINUTE;
2232         trem -= tm->tm_min * USECS_PER_MINUTE;
2233         tm->tm_sec = trem / USECS_PER_SEC;
2234         *fsec = trem - tm->tm_sec * USECS_PER_SEC;
2235 #else
2236 recalc:
2237         TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
2238         TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
2239         TMODULO(trem, tm->tm_sec, 1.0);
2240         trem = TIMEROUND(trem);
2241         /* roundoff may need to propagate to higher-order fields */
2242         if (trem >= 1.0)
2243         {
2244                 trem = ceil(time->time);
2245                 goto recalc;
2246         }
2247         *fsec = trem;
2248 #endif
2249
2250         if (tzp != NULL)
2251                 *tzp = time->zone;
2252
2253         return 0;
2254 }
2255
2256 /* timetz_scale()
2257  * Adjust time type for specified scale factor.
2258  * Used by PostgreSQL type system to stuff columns.
2259  */
2260 Datum
2261 timetz_scale(PG_FUNCTION_ARGS)
2262 {
2263         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2264         int32           typmod = PG_GETARG_INT32(1);
2265         TimeTzADT  *result;
2266
2267         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2268
2269         result->time = time->time;
2270         result->zone = time->zone;
2271
2272         AdjustTimeForTypmod(&(result->time), typmod);
2273
2274         PG_RETURN_TIMETZADT_P(result);
2275 }
2276
2277
2278 static int
2279 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
2280 {
2281         TimeOffset      t1,
2282                                 t2;
2283
2284         /* Primary sort is by true (GMT-equivalent) time */
2285 #ifdef HAVE_INT64_TIMESTAMP
2286         t1 = time1->time + (time1->zone * USECS_PER_SEC);
2287         t2 = time2->time + (time2->zone * USECS_PER_SEC);
2288 #else
2289         t1 = time1->time + time1->zone;
2290         t2 = time2->time + time2->zone;
2291 #endif
2292
2293         if (t1 > t2)
2294                 return 1;
2295         if (t1 < t2)
2296                 return -1;
2297
2298         /*
2299          * If same GMT time, sort by timezone; we only want to say that two
2300          * timetz's are equal if both the time and zone parts are equal.
2301          */
2302         if (time1->zone > time2->zone)
2303                 return 1;
2304         if (time1->zone < time2->zone)
2305                 return -1;
2306
2307         return 0;
2308 }
2309
2310 Datum
2311 timetz_eq(PG_FUNCTION_ARGS)
2312 {
2313         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2314         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2315
2316         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2317 }
2318
2319 Datum
2320 timetz_ne(PG_FUNCTION_ARGS)
2321 {
2322         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2323         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2324
2325         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2326 }
2327
2328 Datum
2329 timetz_lt(PG_FUNCTION_ARGS)
2330 {
2331         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2332         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2333
2334         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2335 }
2336
2337 Datum
2338 timetz_le(PG_FUNCTION_ARGS)
2339 {
2340         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2341         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2342
2343         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2344 }
2345
2346 Datum
2347 timetz_gt(PG_FUNCTION_ARGS)
2348 {
2349         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2350         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2351
2352         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2353 }
2354
2355 Datum
2356 timetz_ge(PG_FUNCTION_ARGS)
2357 {
2358         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2359         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2360
2361         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2362 }
2363
2364 Datum
2365 timetz_cmp(PG_FUNCTION_ARGS)
2366 {
2367         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2368         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2369
2370         PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2371 }
2372
2373 Datum
2374 timetz_hash(PG_FUNCTION_ARGS)
2375 {
2376         TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
2377         uint32          thash;
2378
2379         /*
2380          * To avoid any problems with padding bytes in the struct, we figure the
2381          * field hashes separately and XOR them.  This also provides a convenient
2382          * framework for dealing with the fact that the time field might be either
2383          * double or int64.
2384          */
2385 #ifdef HAVE_INT64_TIMESTAMP
2386         thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2387                                                                                            Int64GetDatumFast(key->time)));
2388 #else
2389         thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
2390                                                                                          Float8GetDatumFast(key->time)));
2391 #endif
2392         thash ^= DatumGetUInt32(hash_uint32(key->zone));
2393         PG_RETURN_UINT32(thash);
2394 }
2395
2396 Datum
2397 timetz_larger(PG_FUNCTION_ARGS)
2398 {
2399         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2400         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2401         TimeTzADT  *result;
2402
2403         if (timetz_cmp_internal(time1, time2) > 0)
2404                 result = time1;
2405         else
2406                 result = time2;
2407         PG_RETURN_TIMETZADT_P(result);
2408 }
2409
2410 Datum
2411 timetz_smaller(PG_FUNCTION_ARGS)
2412 {
2413         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2414         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2415         TimeTzADT  *result;
2416
2417         if (timetz_cmp_internal(time1, time2) < 0)
2418                 result = time1;
2419         else
2420                 result = time2;
2421         PG_RETURN_TIMETZADT_P(result);
2422 }
2423
2424 /* timetz_pl_interval()
2425  * Add interval to timetz.
2426  */
2427 Datum
2428 timetz_pl_interval(PG_FUNCTION_ARGS)
2429 {
2430         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2431         Interval   *span = PG_GETARG_INTERVAL_P(1);
2432         TimeTzADT  *result;
2433
2434 #ifndef HAVE_INT64_TIMESTAMP
2435         TimeTzADT       time1;
2436 #endif
2437
2438         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2439
2440 #ifdef HAVE_INT64_TIMESTAMP
2441         result->time = time->time + span->time;
2442         result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2443         if (result->time < INT64CONST(0))
2444                 result->time += USECS_PER_DAY;
2445 #else
2446         result->time = time->time + span->time;
2447         TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
2448         if (result->time < 0)
2449                 result->time += SECS_PER_DAY;
2450 #endif
2451
2452         result->zone = time->zone;
2453
2454         PG_RETURN_TIMETZADT_P(result);
2455 }
2456
2457 /* timetz_mi_interval()
2458  * Subtract interval from timetz.
2459  */
2460 Datum
2461 timetz_mi_interval(PG_FUNCTION_ARGS)
2462 {
2463         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2464         Interval   *span = PG_GETARG_INTERVAL_P(1);
2465         TimeTzADT  *result;
2466
2467 #ifndef HAVE_INT64_TIMESTAMP
2468         TimeTzADT       time1;
2469 #endif
2470
2471         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2472
2473 #ifdef HAVE_INT64_TIMESTAMP
2474         result->time = time->time - span->time;
2475         result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2476         if (result->time < INT64CONST(0))
2477                 result->time += USECS_PER_DAY;
2478 #else
2479         result->time = time->time - span->time;
2480         TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
2481         if (result->time < 0)
2482                 result->time += SECS_PER_DAY;
2483 #endif
2484
2485         result->zone = time->zone;
2486
2487         PG_RETURN_TIMETZADT_P(result);
2488 }
2489
2490 /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
2491  *
2492  * Algorithm is per SQL spec.  This is much harder than you'd think
2493  * because the spec requires us to deliver a non-null answer in some cases
2494  * where some of the inputs are null.
2495  */
2496 Datum
2497 overlaps_timetz(PG_FUNCTION_ARGS)
2498 {
2499         /*
2500          * The arguments are TimeTzADT *, but we leave them as generic Datums for
2501          * convenience of notation --- and to avoid dereferencing nulls.
2502          */
2503         Datum           ts1 = PG_GETARG_DATUM(0);
2504         Datum           te1 = PG_GETARG_DATUM(1);
2505         Datum           ts2 = PG_GETARG_DATUM(2);
2506         Datum           te2 = PG_GETARG_DATUM(3);
2507         bool            ts1IsNull = PG_ARGISNULL(0);
2508         bool            te1IsNull = PG_ARGISNULL(1);
2509         bool            ts2IsNull = PG_ARGISNULL(2);
2510         bool            te2IsNull = PG_ARGISNULL(3);
2511
2512 #define TIMETZ_GT(t1,t2) \
2513         DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2514 #define TIMETZ_LT(t1,t2) \
2515         DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2516
2517         /*
2518          * If both endpoints of interval 1 are null, the result is null (unknown).
2519          * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2520          * take ts1 as the lesser endpoint.
2521          */
2522         if (ts1IsNull)
2523         {
2524                 if (te1IsNull)
2525                         PG_RETURN_NULL();
2526                 /* swap null for non-null */
2527                 ts1 = te1;
2528                 te1IsNull = true;
2529         }
2530         else if (!te1IsNull)
2531         {
2532                 if (TIMETZ_GT(ts1, te1))
2533                 {
2534                         Datum           tt = ts1;
2535
2536                         ts1 = te1;
2537                         te1 = tt;
2538                 }
2539         }
2540
2541         /* Likewise for interval 2. */
2542         if (ts2IsNull)
2543         {
2544                 if (te2IsNull)
2545                         PG_RETURN_NULL();
2546                 /* swap null for non-null */
2547                 ts2 = te2;
2548                 te2IsNull = true;
2549         }
2550         else if (!te2IsNull)
2551         {
2552                 if (TIMETZ_GT(ts2, te2))
2553                 {
2554                         Datum           tt = ts2;
2555
2556                         ts2 = te2;
2557                         te2 = tt;
2558                 }
2559         }
2560
2561         /*
2562          * At this point neither ts1 nor ts2 is null, so we can consider three
2563          * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2564          */
2565         if (TIMETZ_GT(ts1, ts2))
2566         {
2567                 /*
2568                  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2569                  * in the presence of nulls it's not quite completely so.
2570                  */
2571                 if (te2IsNull)
2572                         PG_RETURN_NULL();
2573                 if (TIMETZ_LT(ts1, te2))
2574                         PG_RETURN_BOOL(true);
2575                 if (te1IsNull)
2576                         PG_RETURN_NULL();
2577
2578                 /*
2579                  * If te1 is not null then we had ts1 <= te1 above, and we just found
2580                  * ts1 >= te2, hence te1 >= te2.
2581                  */
2582                 PG_RETURN_BOOL(false);
2583         }
2584         else if (TIMETZ_LT(ts1, ts2))
2585         {
2586                 /* This case is ts2 < te1 OR te2 < te1 */
2587                 if (te1IsNull)
2588                         PG_RETURN_NULL();
2589                 if (TIMETZ_LT(ts2, te1))
2590                         PG_RETURN_BOOL(true);
2591                 if (te2IsNull)
2592                         PG_RETURN_NULL();
2593
2594                 /*
2595                  * If te2 is not null then we had ts2 <= te2 above, and we just found
2596                  * ts2 >= te1, hence te2 >= te1.
2597                  */
2598                 PG_RETURN_BOOL(false);
2599         }
2600         else
2601         {
2602                 /*
2603                  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2604                  * rather silly way of saying "true if both are nonnull, else null".
2605                  */
2606                 if (te1IsNull || te2IsNull)
2607                         PG_RETURN_NULL();
2608                 PG_RETURN_BOOL(true);
2609         }
2610
2611 #undef TIMETZ_GT
2612 #undef TIMETZ_LT
2613 }
2614
2615
2616 Datum
2617 timetz_time(PG_FUNCTION_ARGS)
2618 {
2619         TimeTzADT  *timetz = PG_GETARG_TIMETZADT_P(0);
2620         TimeADT         result;
2621
2622         /* swallow the time zone and just return the time */
2623         result = timetz->time;
2624
2625         PG_RETURN_TIMEADT(result);
2626 }
2627
2628
2629 Datum
2630 time_timetz(PG_FUNCTION_ARGS)
2631 {
2632         TimeADT         time = PG_GETARG_TIMEADT(0);
2633         TimeTzADT  *result;
2634         struct pg_tm tt,
2635                            *tm = &tt;
2636         fsec_t          fsec;
2637         int                     tz;
2638
2639         GetCurrentDateTime(tm);
2640         time2tm(time, tm, &fsec);
2641         tz = DetermineTimeZoneOffset(tm, session_timezone);
2642
2643         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2644
2645         result->time = time;
2646         result->zone = tz;
2647
2648         PG_RETURN_TIMETZADT_P(result);
2649 }
2650
2651
2652 /* timestamptz_timetz()
2653  * Convert timestamp to timetz data type.
2654  */
2655 Datum
2656 timestamptz_timetz(PG_FUNCTION_ARGS)
2657 {
2658         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2659         TimeTzADT  *result;
2660         struct pg_tm tt,
2661                            *tm = &tt;
2662         int                     tz;
2663         fsec_t          fsec;
2664
2665         if (TIMESTAMP_NOT_FINITE(timestamp))
2666                 PG_RETURN_NULL();
2667
2668         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2669                 ereport(ERROR,
2670                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2671                                  errmsg("timestamp out of range")));
2672
2673         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2674
2675         tm2timetz(tm, fsec, tz, result);
2676
2677         PG_RETURN_TIMETZADT_P(result);
2678 }
2679
2680
2681 /* datetimetz_timestamptz()
2682  * Convert date and timetz to timestamp with time zone data type.
2683  * Timestamp is stored in GMT, so add the time zone
2684  * stored with the timetz to the result.
2685  * - thomas 2000-03-10
2686  */
2687 Datum
2688 datetimetz_timestamptz(PG_FUNCTION_ARGS)
2689 {
2690         DateADT         date = PG_GETARG_DATEADT(0);
2691         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2692         TimestampTz result;
2693
2694         if (DATE_IS_NOBEGIN(date))
2695                 TIMESTAMP_NOBEGIN(result);
2696         else if (DATE_IS_NOEND(date))
2697                 TIMESTAMP_NOEND(result);
2698         else
2699         {
2700                 /*
2701                  * Date's range is wider than timestamp's, so check for boundaries.
2702                  * Since dates have the same minimum values as timestamps, only upper
2703                  * boundary need be checked for overflow.
2704                  */
2705                 if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
2706                         ereport(ERROR,
2707                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2708                                          errmsg("date out of range for timestamp")));
2709 #ifdef HAVE_INT64_TIMESTAMP
2710                 result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
2711 #else
2712                 result = date * (double) SECS_PER_DAY + time->time + time->zone;
2713 #endif
2714
2715                 /*
2716                  * Since it is possible to go beyond allowed timestamptz range because
2717                  * of time zone, check for allowed timestamp range after adding tz.
2718                  */
2719                 if (!IS_VALID_TIMESTAMP(result))
2720                         ereport(ERROR,
2721                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2722                                          errmsg("date out of range for timestamp")));
2723         }
2724
2725         PG_RETURN_TIMESTAMP(result);
2726 }
2727
2728
2729 /* timetz_part()
2730  * Extract specified field from time type.
2731  */
2732 Datum
2733 timetz_part(PG_FUNCTION_ARGS)
2734 {
2735         text       *units = PG_GETARG_TEXT_PP(0);
2736         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2737         float8          result;
2738         int                     type,
2739                                 val;
2740         char       *lowunits;
2741
2742         lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2743                                                                                         VARSIZE_ANY_EXHDR(units),
2744                                                                                         false);
2745
2746         type = DecodeUnits(0, lowunits, &val);
2747         if (type == UNKNOWN_FIELD)
2748                 type = DecodeSpecial(0, lowunits, &val);
2749
2750         if (type == UNITS)
2751         {
2752                 double          dummy;
2753                 int                     tz;
2754                 fsec_t          fsec;
2755                 struct pg_tm tt,
2756                                    *tm = &tt;
2757
2758                 timetz2tm(time, tm, &fsec, &tz);
2759
2760                 switch (val)
2761                 {
2762                         case DTK_TZ:
2763                                 result = -tz;
2764                                 break;
2765
2766                         case DTK_TZ_MINUTE:
2767                                 result = -tz;
2768                                 result /= SECS_PER_MINUTE;
2769                                 FMODULO(result, dummy, (double) SECS_PER_MINUTE);
2770                                 break;
2771
2772                         case DTK_TZ_HOUR:
2773                                 dummy = -tz;
2774                                 FMODULO(dummy, result, (double) SECS_PER_HOUR);
2775                                 break;
2776
2777                         case DTK_MICROSEC:
2778 #ifdef HAVE_INT64_TIMESTAMP
2779                                 result = tm->tm_sec * 1000000.0 + fsec;
2780 #else
2781                                 result = (tm->tm_sec + fsec) * 1000000;
2782 #endif
2783                                 break;
2784
2785                         case DTK_MILLISEC:
2786 #ifdef HAVE_INT64_TIMESTAMP
2787                                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
2788 #else
2789                                 result = (tm->tm_sec + fsec) * 1000;
2790 #endif
2791                                 break;
2792
2793                         case DTK_SECOND:
2794 #ifdef HAVE_INT64_TIMESTAMP
2795                                 result = tm->tm_sec + fsec / 1000000.0;
2796 #else
2797                                 result = tm->tm_sec + fsec;
2798 #endif
2799                                 break;
2800
2801                         case DTK_MINUTE:
2802                                 result = tm->tm_min;
2803                                 break;
2804
2805                         case DTK_HOUR:
2806                                 result = tm->tm_hour;
2807                                 break;
2808
2809                         case DTK_DAY:
2810                         case DTK_MONTH:
2811                         case DTK_QUARTER:
2812                         case DTK_YEAR:
2813                         case DTK_DECADE:
2814                         case DTK_CENTURY:
2815                         case DTK_MILLENNIUM:
2816                         default:
2817                                 ereport(ERROR,
2818                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2819                                 errmsg("\"time with time zone\" units \"%s\" not recognized",
2820                                            lowunits)));
2821                                 result = 0;
2822                 }
2823         }
2824         else if (type == RESERV && val == DTK_EPOCH)
2825         {
2826 #ifdef HAVE_INT64_TIMESTAMP
2827                 result = time->time / 1000000.0 + time->zone;
2828 #else
2829                 result = time->time + time->zone;
2830 #endif
2831         }
2832         else
2833         {
2834                 ereport(ERROR,
2835                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2836                                  errmsg("\"time with time zone\" units \"%s\" not recognized",
2837                                                 lowunits)));
2838                 result = 0;
2839         }
2840
2841         PG_RETURN_FLOAT8(result);
2842 }
2843
2844 /* timetz_zone()
2845  * Encode time with time zone type with specified time zone.
2846  * Applies DST rules as of the current date.
2847  */
2848 Datum
2849 timetz_zone(PG_FUNCTION_ARGS)
2850 {
2851         text       *zone = PG_GETARG_TEXT_PP(0);
2852         TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
2853         TimeTzADT  *result;
2854         int                     tz;
2855         char            tzname[TZ_STRLEN_MAX + 1];
2856         char       *lowzone;
2857         int                     type,
2858                                 val;
2859         pg_tz      *tzp;
2860
2861         /*
2862          * Look up the requested timezone.  First we look in the timezone
2863          * abbreviation table (to handle cases like "EST"), and if that fails, we
2864          * look in the timezone database (to handle cases like
2865          * "America/New_York").  (This matches the order in which timestamp input
2866          * checks the cases; it's important because the timezone database unwisely
2867          * uses a few zone names that are identical to offset abbreviations.)
2868          */
2869         text_to_cstring_buffer(zone, tzname, sizeof(tzname));
2870
2871         /* DecodeTimezoneAbbrev requires lowercase input */
2872         lowzone = downcase_truncate_identifier(tzname,
2873                                                                                    strlen(tzname),
2874                                                                                    false);
2875
2876         type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
2877
2878         if (type == TZ || type == DTZ)
2879         {
2880                 /* fixed-offset abbreviation */
2881                 tz = -val;
2882         }
2883         else if (type == DYNTZ)
2884         {
2885                 /* dynamic-offset abbreviation, resolve using current time */
2886                 pg_time_t       now = (pg_time_t) time(NULL);
2887                 struct pg_tm *tm;
2888
2889                 tm = pg_localtime(&now, tzp);
2890                 tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
2891         }
2892         else
2893         {
2894                 /* try it as a full zone name */
2895                 tzp = pg_tzset(tzname);
2896                 if (tzp)
2897                 {
2898                         /* Get the offset-from-GMT that is valid today for the zone */
2899                         pg_time_t       now = (pg_time_t) time(NULL);
2900                         struct pg_tm *tm;
2901
2902                         tm = pg_localtime(&now, tzp);
2903                         tz = -tm->tm_gmtoff;
2904                 }
2905                 else
2906                 {
2907                         ereport(ERROR,
2908                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2909                                          errmsg("time zone \"%s\" not recognized", tzname)));
2910                         tz = 0;                         /* keep compiler quiet */
2911                 }
2912         }
2913
2914         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2915
2916 #ifdef HAVE_INT64_TIMESTAMP
2917         result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
2918         while (result->time < INT64CONST(0))
2919                 result->time += USECS_PER_DAY;
2920         while (result->time >= USECS_PER_DAY)
2921                 result->time -= USECS_PER_DAY;
2922 #else
2923         result->time = t->time + (t->zone - tz);
2924         while (result->time < 0)
2925                 result->time += SECS_PER_DAY;
2926         while (result->time >= SECS_PER_DAY)
2927                 result->time -= SECS_PER_DAY;
2928 #endif
2929
2930         result->zone = tz;
2931
2932         PG_RETURN_TIMETZADT_P(result);
2933 }
2934
2935 /* timetz_izone()
2936  * Encode time with time zone type with specified time interval as time zone.
2937  */
2938 Datum
2939 timetz_izone(PG_FUNCTION_ARGS)
2940 {
2941         Interval   *zone = PG_GETARG_INTERVAL_P(0);
2942         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2943         TimeTzADT  *result;
2944         int                     tz;
2945
2946         if (zone->month != 0 || zone->day != 0)
2947                 ereport(ERROR,
2948                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2949                   errmsg("interval time zone \"%s\" must not include months or days",
2950                                  DatumGetCString(DirectFunctionCall1(interval_out,
2951                                                                                                   PointerGetDatum(zone))))));
2952
2953 #ifdef HAVE_INT64_TIMESTAMP
2954         tz = -(zone->time / USECS_PER_SEC);
2955 #else
2956         tz = -(zone->time);
2957 #endif
2958
2959         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2960
2961 #ifdef HAVE_INT64_TIMESTAMP
2962         result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
2963         while (result->time < INT64CONST(0))
2964                 result->time += USECS_PER_DAY;
2965         while (result->time >= USECS_PER_DAY)
2966                 result->time -= USECS_PER_DAY;
2967 #else
2968         result->time = time->time + (time->zone - tz);
2969         while (result->time < 0)
2970                 result->time += SECS_PER_DAY;
2971         while (result->time >= SECS_PER_DAY)
2972                 result->time -= SECS_PER_DAY;
2973 #endif
2974
2975         result->zone = tz;
2976
2977         PG_RETURN_TIMETZADT_P(result);
2978 }