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