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