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