Header And Logo

PostgreSQL
| The world's most advanced open source database.

date.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * date.c
00004  *    implements DATE and TIME data types specified in SQL standard
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994-5, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/date.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "postgres.h"
00017 
00018 #include <ctype.h>
00019 #include <limits.h>
00020 #include <float.h>
00021 #include <time.h>
00022 
00023 #include "access/hash.h"
00024 #include "libpq/pqformat.h"
00025 #include "miscadmin.h"
00026 #include "parser/scansup.h"
00027 #include "utils/array.h"
00028 #include "utils/builtins.h"
00029 #include "utils/date.h"
00030 #include "utils/datetime.h"
00031 #include "utils/nabstime.h"
00032 #include "utils/sortsupport.h"
00033 
00034 /*
00035  * gcc's -ffast-math switch breaks routines that expect exact results from
00036  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
00037  */
00038 #ifdef __FAST_MATH__
00039 #error -ffast-math is known to break this code
00040 #endif
00041 
00042 
00043 static void EncodeSpecialDate(DateADT dt, char *str);
00044 static int  time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
00045 static int  timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
00046 static int  tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
00047 static int  tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
00048 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
00049 
00050 
00051 /* common code for timetypmodin and timetztypmodin */
00052 static int32
00053 anytime_typmodin(bool istz, ArrayType *ta)
00054 {
00055     int32       typmod;
00056     int32      *tl;
00057     int         n;
00058 
00059     tl = ArrayGetIntegerTypmods(ta, &n);
00060 
00061     /*
00062      * we're not too tense about good error message here because grammar
00063      * shouldn't allow wrong number of modifiers for TIME
00064      */
00065     if (n != 1)
00066         ereport(ERROR,
00067                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00068                  errmsg("invalid type modifier")));
00069 
00070     if (*tl < 0)
00071         ereport(ERROR,
00072                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00073                  errmsg("TIME(%d)%s precision must not be negative",
00074                         *tl, (istz ? " WITH TIME ZONE" : ""))));
00075     if (*tl > MAX_TIME_PRECISION)
00076     {
00077         ereport(WARNING,
00078                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00079                  errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
00080                         *tl, (istz ? " WITH TIME ZONE" : ""),
00081                         MAX_TIME_PRECISION)));
00082         typmod = MAX_TIME_PRECISION;
00083     }
00084     else
00085         typmod = *tl;
00086 
00087     return typmod;
00088 }
00089 
00090 /* common code for timetypmodout and timetztypmodout */
00091 static char *
00092 anytime_typmodout(bool istz, int32 typmod)
00093 {
00094     char       *res = (char *) palloc(64);
00095     const char *tz = istz ? " with time zone" : " without time zone";
00096 
00097     if (typmod >= 0)
00098         snprintf(res, 64, "(%d)%s", (int) typmod, tz);
00099     else
00100         snprintf(res, 64, "%s", tz);
00101     return res;
00102 }
00103 
00104 
00105 /*****************************************************************************
00106  *   Date ADT
00107  *****************************************************************************/
00108 
00109 
00110 /* date_in()
00111  * Given date text string, convert to internal date format.
00112  */
00113 Datum
00114 date_in(PG_FUNCTION_ARGS)
00115 {
00116     char       *str = PG_GETARG_CSTRING(0);
00117     DateADT     date;
00118     fsec_t      fsec;
00119     struct pg_tm tt,
00120                *tm = &tt;
00121     int         tzp;
00122     int         dtype;
00123     int         nf;
00124     int         dterr;
00125     char       *field[MAXDATEFIELDS];
00126     int         ftype[MAXDATEFIELDS];
00127     char        workbuf[MAXDATELEN + 1];
00128 
00129     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
00130                           field, ftype, MAXDATEFIELDS, &nf);
00131     if (dterr == 0)
00132         dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
00133     if (dterr != 0)
00134         DateTimeParseError(dterr, str, "date");
00135 
00136     switch (dtype)
00137     {
00138         case DTK_DATE:
00139             break;
00140 
00141         case DTK_CURRENT:
00142             ereport(ERROR,
00143                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00144               errmsg("date/time value \"current\" is no longer supported")));
00145 
00146             GetCurrentDateTime(tm);
00147             break;
00148 
00149         case DTK_EPOCH:
00150             GetEpochTime(tm);
00151             break;
00152 
00153         case DTK_LATE:
00154             DATE_NOEND(date);
00155             PG_RETURN_DATEADT(date);
00156 
00157         case DTK_EARLY:
00158             DATE_NOBEGIN(date);
00159             PG_RETURN_DATEADT(date);
00160 
00161         default:
00162             DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
00163             break;
00164     }
00165 
00166     if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
00167         ereport(ERROR,
00168                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00169                  errmsg("date out of range: \"%s\"", str)));
00170 
00171     date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
00172 
00173     PG_RETURN_DATEADT(date);
00174 }
00175 
00176 /* date_out()
00177  * Given internal format date, convert to text string.
00178  */
00179 Datum
00180 date_out(PG_FUNCTION_ARGS)
00181 {
00182     DateADT     date = PG_GETARG_DATEADT(0);
00183     char       *result;
00184     struct pg_tm tt,
00185                *tm = &tt;
00186     char        buf[MAXDATELEN + 1];
00187 
00188     if (DATE_NOT_FINITE(date))
00189         EncodeSpecialDate(date, buf);
00190     else
00191     {
00192         j2date(date + POSTGRES_EPOCH_JDATE,
00193                &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
00194         EncodeDateOnly(tm, DateStyle, buf);
00195     }
00196 
00197     result = pstrdup(buf);
00198     PG_RETURN_CSTRING(result);
00199 }
00200 
00201 /*
00202  *      date_recv           - converts external binary format to date
00203  */
00204 Datum
00205 date_recv(PG_FUNCTION_ARGS)
00206 {
00207     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00208     DateADT     result;
00209 
00210     result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
00211 
00212     /* Limit to the same range that date_in() accepts. */
00213     if (DATE_NOT_FINITE(result))
00214          /* ok */ ;
00215     else if (result < -POSTGRES_EPOCH_JDATE ||
00216              result >= JULIAN_MAX - POSTGRES_EPOCH_JDATE)
00217         ereport(ERROR,
00218                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00219                  errmsg("date out of range")));
00220 
00221     PG_RETURN_DATEADT(result);
00222 }
00223 
00224 /*
00225  *      date_send           - converts date to binary format
00226  */
00227 Datum
00228 date_send(PG_FUNCTION_ARGS)
00229 {
00230     DateADT     date = PG_GETARG_DATEADT(0);
00231     StringInfoData buf;
00232 
00233     pq_begintypsend(&buf);
00234     pq_sendint(&buf, date, sizeof(date));
00235     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00236 }
00237 
00238 /*
00239  * Convert reserved date values to string.
00240  */
00241 static void
00242 EncodeSpecialDate(DateADT dt, char *str)
00243 {
00244     if (DATE_IS_NOBEGIN(dt))
00245         strcpy(str, EARLY);
00246     else if (DATE_IS_NOEND(dt))
00247         strcpy(str, LATE);
00248     else    /* shouldn't happen */
00249         elog(ERROR, "invalid argument for EncodeSpecialDate");
00250 }
00251 
00252 
00253 /*
00254  * Comparison functions for dates
00255  */
00256 
00257 Datum
00258 date_eq(PG_FUNCTION_ARGS)
00259 {
00260     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00261     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00262 
00263     PG_RETURN_BOOL(dateVal1 == dateVal2);
00264 }
00265 
00266 Datum
00267 date_ne(PG_FUNCTION_ARGS)
00268 {
00269     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00270     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00271 
00272     PG_RETURN_BOOL(dateVal1 != dateVal2);
00273 }
00274 
00275 Datum
00276 date_lt(PG_FUNCTION_ARGS)
00277 {
00278     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00279     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00280 
00281     PG_RETURN_BOOL(dateVal1 < dateVal2);
00282 }
00283 
00284 Datum
00285 date_le(PG_FUNCTION_ARGS)
00286 {
00287     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00288     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00289 
00290     PG_RETURN_BOOL(dateVal1 <= dateVal2);
00291 }
00292 
00293 Datum
00294 date_gt(PG_FUNCTION_ARGS)
00295 {
00296     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00297     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00298 
00299     PG_RETURN_BOOL(dateVal1 > dateVal2);
00300 }
00301 
00302 Datum
00303 date_ge(PG_FUNCTION_ARGS)
00304 {
00305     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00306     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00307 
00308     PG_RETURN_BOOL(dateVal1 >= dateVal2);
00309 }
00310 
00311 Datum
00312 date_cmp(PG_FUNCTION_ARGS)
00313 {
00314     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00315     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00316 
00317     if (dateVal1 < dateVal2)
00318         PG_RETURN_INT32(-1);
00319     else if (dateVal1 > dateVal2)
00320         PG_RETURN_INT32(1);
00321     PG_RETURN_INT32(0);
00322 }
00323 
00324 static int
00325 date_fastcmp(Datum x, Datum y, SortSupport ssup)
00326 {
00327     DateADT     a = DatumGetDateADT(x);
00328     DateADT     b = DatumGetDateADT(y);
00329 
00330     if (a < b)
00331         return -1;
00332     else if (a > b)
00333         return 1;
00334     return 0;
00335 }
00336 
00337 Datum
00338 date_sortsupport(PG_FUNCTION_ARGS)
00339 {
00340     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
00341 
00342     ssup->comparator = date_fastcmp;
00343     PG_RETURN_VOID();
00344 }
00345 
00346 Datum
00347 date_finite(PG_FUNCTION_ARGS)
00348 {
00349     DateADT     date = PG_GETARG_DATEADT(0);
00350 
00351     PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
00352 }
00353 
00354 Datum
00355 date_larger(PG_FUNCTION_ARGS)
00356 {
00357     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00358     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00359 
00360     PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
00361 }
00362 
00363 Datum
00364 date_smaller(PG_FUNCTION_ARGS)
00365 {
00366     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00367     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00368 
00369     PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
00370 }
00371 
00372 /* Compute difference between two dates in days.
00373  */
00374 Datum
00375 date_mi(PG_FUNCTION_ARGS)
00376 {
00377     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
00378     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
00379 
00380     if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
00381         ereport(ERROR,
00382                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00383                  errmsg("cannot subtract infinite dates")));
00384 
00385     PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
00386 }
00387 
00388 /* Add a number of days to a date, giving a new date.
00389  * Must handle both positive and negative numbers of days.
00390  */
00391 Datum
00392 date_pli(PG_FUNCTION_ARGS)
00393 {
00394     DateADT     dateVal = PG_GETARG_DATEADT(0);
00395     int32       days = PG_GETARG_INT32(1);
00396 
00397     if (DATE_NOT_FINITE(dateVal))
00398         days = 0;               /* can't change infinity */
00399 
00400     PG_RETURN_DATEADT(dateVal + days);
00401 }
00402 
00403 /* Subtract a number of days from a date, giving a new date.
00404  */
00405 Datum
00406 date_mii(PG_FUNCTION_ARGS)
00407 {
00408     DateADT     dateVal = PG_GETARG_DATEADT(0);
00409     int32       days = PG_GETARG_INT32(1);
00410 
00411     if (DATE_NOT_FINITE(dateVal))
00412         days = 0;               /* can't change infinity */
00413 
00414     PG_RETURN_DATEADT(dateVal - days);
00415 }
00416 
00417 /*
00418  * Internal routines for promoting date to timestamp and timestamp with
00419  * time zone
00420  */
00421 
00422 static Timestamp
00423 date2timestamp(DateADT dateVal)
00424 {
00425     Timestamp   result;
00426 
00427     if (DATE_IS_NOBEGIN(dateVal))
00428         TIMESTAMP_NOBEGIN(result);
00429     else if (DATE_IS_NOEND(dateVal))
00430         TIMESTAMP_NOEND(result);
00431     else
00432     {
00433 #ifdef HAVE_INT64_TIMESTAMP
00434         /* date is days since 2000, timestamp is microseconds since same... */
00435         result = dateVal * USECS_PER_DAY;
00436         /* Date's range is wider than timestamp's, so check for overflow */
00437         if (result / USECS_PER_DAY != dateVal)
00438             ereport(ERROR,
00439                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00440                      errmsg("date out of range for timestamp")));
00441 #else
00442         /* date is days since 2000, timestamp is seconds since same... */
00443         result = dateVal * (double) SECS_PER_DAY;
00444 #endif
00445     }
00446 
00447     return result;
00448 }
00449 
00450 static TimestampTz
00451 date2timestamptz(DateADT dateVal)
00452 {
00453     TimestampTz result;
00454     struct pg_tm tt,
00455                *tm = &tt;
00456     int         tz;
00457 
00458     if (DATE_IS_NOBEGIN(dateVal))
00459         TIMESTAMP_NOBEGIN(result);
00460     else if (DATE_IS_NOEND(dateVal))
00461         TIMESTAMP_NOEND(result);
00462     else
00463     {
00464         j2date(dateVal + POSTGRES_EPOCH_JDATE,
00465                &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
00466         tm->tm_hour = 0;
00467         tm->tm_min = 0;
00468         tm->tm_sec = 0;
00469         tz = DetermineTimeZoneOffset(tm, session_timezone);
00470 
00471 #ifdef HAVE_INT64_TIMESTAMP
00472         result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
00473         /* Date's range is wider than timestamp's, so check for overflow */
00474         if ((result - tz * USECS_PER_SEC) / USECS_PER_DAY != dateVal)
00475             ereport(ERROR,
00476                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00477                      errmsg("date out of range for timestamp")));
00478 #else
00479         result = dateVal * (double) SECS_PER_DAY + tz;
00480 #endif
00481     }
00482 
00483     return result;
00484 }
00485 
00486 /*
00487  * date2timestamp_no_overflow
00488  *
00489  * This is chartered to produce a double value that is numerically
00490  * equivalent to the corresponding Timestamp value, if the date is in the
00491  * valid range of Timestamps, but in any case not throw an overflow error.
00492  * We can do this since the numerical range of double is greater than
00493  * that of non-erroneous timestamps.  The results are currently only
00494  * used for statistical estimation purposes.
00495  */
00496 double
00497 date2timestamp_no_overflow(DateADT dateVal)
00498 {
00499     double      result;
00500 
00501     if (DATE_IS_NOBEGIN(dateVal))
00502         result = -DBL_MAX;
00503     else if (DATE_IS_NOEND(dateVal))
00504         result = DBL_MAX;
00505     else
00506     {
00507 #ifdef HAVE_INT64_TIMESTAMP
00508         /* date is days since 2000, timestamp is microseconds since same... */
00509         result = dateVal * (double) USECS_PER_DAY;
00510 #else
00511         /* date is days since 2000, timestamp is seconds since same... */
00512         result = dateVal * (double) SECS_PER_DAY;
00513 #endif
00514     }
00515 
00516     return result;
00517 }
00518 
00519 
00520 /*
00521  * Crosstype comparison functions for dates
00522  */
00523 
00524 Datum
00525 date_eq_timestamp(PG_FUNCTION_ARGS)
00526 {
00527     DateADT     dateVal = PG_GETARG_DATEADT(0);
00528     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00529     Timestamp   dt1;
00530 
00531     dt1 = date2timestamp(dateVal);
00532 
00533     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
00534 }
00535 
00536 Datum
00537 date_ne_timestamp(PG_FUNCTION_ARGS)
00538 {
00539     DateADT     dateVal = PG_GETARG_DATEADT(0);
00540     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00541     Timestamp   dt1;
00542 
00543     dt1 = date2timestamp(dateVal);
00544 
00545     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
00546 }
00547 
00548 Datum
00549 date_lt_timestamp(PG_FUNCTION_ARGS)
00550 {
00551     DateADT     dateVal = PG_GETARG_DATEADT(0);
00552     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00553     Timestamp   dt1;
00554 
00555     dt1 = date2timestamp(dateVal);
00556 
00557     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
00558 }
00559 
00560 Datum
00561 date_gt_timestamp(PG_FUNCTION_ARGS)
00562 {
00563     DateADT     dateVal = PG_GETARG_DATEADT(0);
00564     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00565     Timestamp   dt1;
00566 
00567     dt1 = date2timestamp(dateVal);
00568 
00569     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
00570 }
00571 
00572 Datum
00573 date_le_timestamp(PG_FUNCTION_ARGS)
00574 {
00575     DateADT     dateVal = PG_GETARG_DATEADT(0);
00576     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00577     Timestamp   dt1;
00578 
00579     dt1 = date2timestamp(dateVal);
00580 
00581     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
00582 }
00583 
00584 Datum
00585 date_ge_timestamp(PG_FUNCTION_ARGS)
00586 {
00587     DateADT     dateVal = PG_GETARG_DATEADT(0);
00588     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00589     Timestamp   dt1;
00590 
00591     dt1 = date2timestamp(dateVal);
00592 
00593     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
00594 }
00595 
00596 Datum
00597 date_cmp_timestamp(PG_FUNCTION_ARGS)
00598 {
00599     DateADT     dateVal = PG_GETARG_DATEADT(0);
00600     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
00601     Timestamp   dt1;
00602 
00603     dt1 = date2timestamp(dateVal);
00604 
00605     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
00606 }
00607 
00608 Datum
00609 date_eq_timestamptz(PG_FUNCTION_ARGS)
00610 {
00611     DateADT     dateVal = PG_GETARG_DATEADT(0);
00612     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00613     TimestampTz dt1;
00614 
00615     dt1 = date2timestamptz(dateVal);
00616 
00617     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
00618 }
00619 
00620 Datum
00621 date_ne_timestamptz(PG_FUNCTION_ARGS)
00622 {
00623     DateADT     dateVal = PG_GETARG_DATEADT(0);
00624     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00625     TimestampTz dt1;
00626 
00627     dt1 = date2timestamptz(dateVal);
00628 
00629     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
00630 }
00631 
00632 Datum
00633 date_lt_timestamptz(PG_FUNCTION_ARGS)
00634 {
00635     DateADT     dateVal = PG_GETARG_DATEADT(0);
00636     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00637     TimestampTz dt1;
00638 
00639     dt1 = date2timestamptz(dateVal);
00640 
00641     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
00642 }
00643 
00644 Datum
00645 date_gt_timestamptz(PG_FUNCTION_ARGS)
00646 {
00647     DateADT     dateVal = PG_GETARG_DATEADT(0);
00648     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00649     TimestampTz dt1;
00650 
00651     dt1 = date2timestamptz(dateVal);
00652 
00653     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
00654 }
00655 
00656 Datum
00657 date_le_timestamptz(PG_FUNCTION_ARGS)
00658 {
00659     DateADT     dateVal = PG_GETARG_DATEADT(0);
00660     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00661     TimestampTz dt1;
00662 
00663     dt1 = date2timestamptz(dateVal);
00664 
00665     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
00666 }
00667 
00668 Datum
00669 date_ge_timestamptz(PG_FUNCTION_ARGS)
00670 {
00671     DateADT     dateVal = PG_GETARG_DATEADT(0);
00672     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00673     TimestampTz dt1;
00674 
00675     dt1 = date2timestamptz(dateVal);
00676 
00677     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
00678 }
00679 
00680 Datum
00681 date_cmp_timestamptz(PG_FUNCTION_ARGS)
00682 {
00683     DateADT     dateVal = PG_GETARG_DATEADT(0);
00684     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
00685     TimestampTz dt1;
00686 
00687     dt1 = date2timestamptz(dateVal);
00688 
00689     PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
00690 }
00691 
00692 Datum
00693 timestamp_eq_date(PG_FUNCTION_ARGS)
00694 {
00695     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00696     DateADT     dateVal = PG_GETARG_DATEADT(1);
00697     Timestamp   dt2;
00698 
00699     dt2 = date2timestamp(dateVal);
00700 
00701     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
00702 }
00703 
00704 Datum
00705 timestamp_ne_date(PG_FUNCTION_ARGS)
00706 {
00707     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00708     DateADT     dateVal = PG_GETARG_DATEADT(1);
00709     Timestamp   dt2;
00710 
00711     dt2 = date2timestamp(dateVal);
00712 
00713     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
00714 }
00715 
00716 Datum
00717 timestamp_lt_date(PG_FUNCTION_ARGS)
00718 {
00719     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00720     DateADT     dateVal = PG_GETARG_DATEADT(1);
00721     Timestamp   dt2;
00722 
00723     dt2 = date2timestamp(dateVal);
00724 
00725     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
00726 }
00727 
00728 Datum
00729 timestamp_gt_date(PG_FUNCTION_ARGS)
00730 {
00731     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00732     DateADT     dateVal = PG_GETARG_DATEADT(1);
00733     Timestamp   dt2;
00734 
00735     dt2 = date2timestamp(dateVal);
00736 
00737     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
00738 }
00739 
00740 Datum
00741 timestamp_le_date(PG_FUNCTION_ARGS)
00742 {
00743     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00744     DateADT     dateVal = PG_GETARG_DATEADT(1);
00745     Timestamp   dt2;
00746 
00747     dt2 = date2timestamp(dateVal);
00748 
00749     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
00750 }
00751 
00752 Datum
00753 timestamp_ge_date(PG_FUNCTION_ARGS)
00754 {
00755     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00756     DateADT     dateVal = PG_GETARG_DATEADT(1);
00757     Timestamp   dt2;
00758 
00759     dt2 = date2timestamp(dateVal);
00760 
00761     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
00762 }
00763 
00764 Datum
00765 timestamp_cmp_date(PG_FUNCTION_ARGS)
00766 {
00767     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
00768     DateADT     dateVal = PG_GETARG_DATEADT(1);
00769     Timestamp   dt2;
00770 
00771     dt2 = date2timestamp(dateVal);
00772 
00773     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
00774 }
00775 
00776 Datum
00777 timestamptz_eq_date(PG_FUNCTION_ARGS)
00778 {
00779     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00780     DateADT     dateVal = PG_GETARG_DATEADT(1);
00781     TimestampTz dt2;
00782 
00783     dt2 = date2timestamptz(dateVal);
00784 
00785     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
00786 }
00787 
00788 Datum
00789 timestamptz_ne_date(PG_FUNCTION_ARGS)
00790 {
00791     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00792     DateADT     dateVal = PG_GETARG_DATEADT(1);
00793     TimestampTz dt2;
00794 
00795     dt2 = date2timestamptz(dateVal);
00796 
00797     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
00798 }
00799 
00800 Datum
00801 timestamptz_lt_date(PG_FUNCTION_ARGS)
00802 {
00803     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00804     DateADT     dateVal = PG_GETARG_DATEADT(1);
00805     TimestampTz dt2;
00806 
00807     dt2 = date2timestamptz(dateVal);
00808 
00809     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
00810 }
00811 
00812 Datum
00813 timestamptz_gt_date(PG_FUNCTION_ARGS)
00814 {
00815     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00816     DateADT     dateVal = PG_GETARG_DATEADT(1);
00817     TimestampTz dt2;
00818 
00819     dt2 = date2timestamptz(dateVal);
00820 
00821     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
00822 }
00823 
00824 Datum
00825 timestamptz_le_date(PG_FUNCTION_ARGS)
00826 {
00827     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00828     DateADT     dateVal = PG_GETARG_DATEADT(1);
00829     TimestampTz dt2;
00830 
00831     dt2 = date2timestamptz(dateVal);
00832 
00833     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
00834 }
00835 
00836 Datum
00837 timestamptz_ge_date(PG_FUNCTION_ARGS)
00838 {
00839     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00840     DateADT     dateVal = PG_GETARG_DATEADT(1);
00841     TimestampTz dt2;
00842 
00843     dt2 = date2timestamptz(dateVal);
00844 
00845     PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
00846 }
00847 
00848 Datum
00849 timestamptz_cmp_date(PG_FUNCTION_ARGS)
00850 {
00851     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
00852     DateADT     dateVal = PG_GETARG_DATEADT(1);
00853     TimestampTz dt2;
00854 
00855     dt2 = date2timestamptz(dateVal);
00856 
00857     PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
00858 }
00859 
00860 
00861 /* Add an interval to a date, giving a new date.
00862  * Must handle both positive and negative intervals.
00863  *
00864  * We implement this by promoting the date to timestamp (without time zone)
00865  * and then using the timestamp plus interval function.
00866  */
00867 Datum
00868 date_pl_interval(PG_FUNCTION_ARGS)
00869 {
00870     DateADT     dateVal = PG_GETARG_DATEADT(0);
00871     Interval   *span = PG_GETARG_INTERVAL_P(1);
00872     Timestamp   dateStamp;
00873 
00874     dateStamp = date2timestamp(dateVal);
00875 
00876     return DirectFunctionCall2(timestamp_pl_interval,
00877                                TimestampGetDatum(dateStamp),
00878                                PointerGetDatum(span));
00879 }
00880 
00881 /* Subtract an interval from a date, giving a new date.
00882  * Must handle both positive and negative intervals.
00883  *
00884  * We implement this by promoting the date to timestamp (without time zone)
00885  * and then using the timestamp minus interval function.
00886  */
00887 Datum
00888 date_mi_interval(PG_FUNCTION_ARGS)
00889 {
00890     DateADT     dateVal = PG_GETARG_DATEADT(0);
00891     Interval   *span = PG_GETARG_INTERVAL_P(1);
00892     Timestamp   dateStamp;
00893 
00894     dateStamp = date2timestamp(dateVal);
00895 
00896     return DirectFunctionCall2(timestamp_mi_interval,
00897                                TimestampGetDatum(dateStamp),
00898                                PointerGetDatum(span));
00899 }
00900 
00901 /* date_timestamp()
00902  * Convert date to timestamp data type.
00903  */
00904 Datum
00905 date_timestamp(PG_FUNCTION_ARGS)
00906 {
00907     DateADT     dateVal = PG_GETARG_DATEADT(0);
00908     Timestamp   result;
00909 
00910     result = date2timestamp(dateVal);
00911 
00912     PG_RETURN_TIMESTAMP(result);
00913 }
00914 
00915 /* timestamp_date()
00916  * Convert timestamp to date data type.
00917  */
00918 Datum
00919 timestamp_date(PG_FUNCTION_ARGS)
00920 {
00921     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
00922     DateADT     result;
00923     struct pg_tm tt,
00924                *tm = &tt;
00925     fsec_t      fsec;
00926 
00927     if (TIMESTAMP_IS_NOBEGIN(timestamp))
00928         DATE_NOBEGIN(result);
00929     else if (TIMESTAMP_IS_NOEND(timestamp))
00930         DATE_NOEND(result);
00931     else
00932     {
00933         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
00934             ereport(ERROR,
00935                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00936                      errmsg("timestamp out of range")));
00937 
00938         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
00939     }
00940 
00941     PG_RETURN_DATEADT(result);
00942 }
00943 
00944 
00945 /* date_timestamptz()
00946  * Convert date to timestamp with time zone data type.
00947  */
00948 Datum
00949 date_timestamptz(PG_FUNCTION_ARGS)
00950 {
00951     DateADT     dateVal = PG_GETARG_DATEADT(0);
00952     TimestampTz result;
00953 
00954     result = date2timestamptz(dateVal);
00955 
00956     PG_RETURN_TIMESTAMP(result);
00957 }
00958 
00959 
00960 /* timestamptz_date()
00961  * Convert timestamp with time zone to date data type.
00962  */
00963 Datum
00964 timestamptz_date(PG_FUNCTION_ARGS)
00965 {
00966     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
00967     DateADT     result;
00968     struct pg_tm tt,
00969                *tm = &tt;
00970     fsec_t      fsec;
00971     int         tz;
00972 
00973     if (TIMESTAMP_IS_NOBEGIN(timestamp))
00974         DATE_NOBEGIN(result);
00975     else if (TIMESTAMP_IS_NOEND(timestamp))
00976         DATE_NOEND(result);
00977     else
00978     {
00979         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
00980             ereport(ERROR,
00981                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00982                      errmsg("timestamp out of range")));
00983 
00984         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
00985     }
00986 
00987     PG_RETURN_DATEADT(result);
00988 }
00989 
00990 
00991 /* abstime_date()
00992  * Convert abstime to date data type.
00993  */
00994 Datum
00995 abstime_date(PG_FUNCTION_ARGS)
00996 {
00997     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
00998     DateADT     result;
00999     struct pg_tm tt,
01000                *tm = &tt;
01001     int         tz;
01002 
01003     switch (abstime)
01004     {
01005         case INVALID_ABSTIME:
01006             ereport(ERROR,
01007                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01008                    errmsg("cannot convert reserved abstime value to date")));
01009             result = 0;         /* keep compiler quiet */
01010             break;
01011 
01012         case NOSTART_ABSTIME:
01013             DATE_NOBEGIN(result);
01014             break;
01015 
01016         case NOEND_ABSTIME:
01017             DATE_NOEND(result);
01018             break;
01019 
01020         default:
01021             abstime2tm(abstime, &tz, tm, NULL);
01022             result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
01023             break;
01024     }
01025 
01026     PG_RETURN_DATEADT(result);
01027 }
01028 
01029 
01030 /*****************************************************************************
01031  *   Time ADT
01032  *****************************************************************************/
01033 
01034 Datum
01035 time_in(PG_FUNCTION_ARGS)
01036 {
01037     char       *str = PG_GETARG_CSTRING(0);
01038 
01039 #ifdef NOT_USED
01040     Oid         typelem = PG_GETARG_OID(1);
01041 #endif
01042     int32       typmod = PG_GETARG_INT32(2);
01043     TimeADT     result;
01044     fsec_t      fsec;
01045     struct pg_tm tt,
01046                *tm = &tt;
01047     int         tz;
01048     int         nf;
01049     int         dterr;
01050     char        workbuf[MAXDATELEN + 1];
01051     char       *field[MAXDATEFIELDS];
01052     int         dtype;
01053     int         ftype[MAXDATEFIELDS];
01054 
01055     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
01056                           field, ftype, MAXDATEFIELDS, &nf);
01057     if (dterr == 0)
01058         dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
01059     if (dterr != 0)
01060         DateTimeParseError(dterr, str, "time");
01061 
01062     tm2time(tm, fsec, &result);
01063     AdjustTimeForTypmod(&result, typmod);
01064 
01065     PG_RETURN_TIMEADT(result);
01066 }
01067 
01068 /* tm2time()
01069  * Convert a tm structure to a time data type.
01070  */
01071 static int
01072 tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
01073 {
01074 #ifdef HAVE_INT64_TIMESTAMP
01075     *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
01076                * USECS_PER_SEC) + fsec;
01077 #else
01078     *result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
01079 #endif
01080     return 0;
01081 }
01082 
01083 /* time2tm()
01084  * Convert time data type to POSIX time structure.
01085  *
01086  * For dates within the range of pg_time_t, convert to the local time zone.
01087  * If out of this range, leave as UTC (in practice that could only happen
01088  * if pg_time_t is just 32 bits) - thomas 97/05/27
01089  */
01090 static int
01091 time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
01092 {
01093 #ifdef HAVE_INT64_TIMESTAMP
01094     tm->tm_hour = time / USECS_PER_HOUR;
01095     time -= tm->tm_hour * USECS_PER_HOUR;
01096     tm->tm_min = time / USECS_PER_MINUTE;
01097     time -= tm->tm_min * USECS_PER_MINUTE;
01098     tm->tm_sec = time / USECS_PER_SEC;
01099     time -= tm->tm_sec * USECS_PER_SEC;
01100     *fsec = time;
01101 #else
01102     double      trem;
01103 
01104 recalc:
01105     trem = time;
01106     TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
01107     TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
01108     TMODULO(trem, tm->tm_sec, 1.0);
01109     trem = TIMEROUND(trem);
01110     /* roundoff may need to propagate to higher-order fields */
01111     if (trem >= 1.0)
01112     {
01113         time = ceil(time);
01114         goto recalc;
01115     }
01116     *fsec = trem;
01117 #endif
01118 
01119     return 0;
01120 }
01121 
01122 Datum
01123 time_out(PG_FUNCTION_ARGS)
01124 {
01125     TimeADT     time = PG_GETARG_TIMEADT(0);
01126     char       *result;
01127     struct pg_tm tt,
01128                *tm = &tt;
01129     fsec_t      fsec;
01130     char        buf[MAXDATELEN + 1];
01131 
01132     time2tm(time, tm, &fsec);
01133     EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
01134 
01135     result = pstrdup(buf);
01136     PG_RETURN_CSTRING(result);
01137 }
01138 
01139 /*
01140  *      time_recv           - converts external binary format to time
01141  *
01142  * We make no attempt to provide compatibility between int and float
01143  * time representations ...
01144  */
01145 Datum
01146 time_recv(PG_FUNCTION_ARGS)
01147 {
01148     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
01149 
01150 #ifdef NOT_USED
01151     Oid         typelem = PG_GETARG_OID(1);
01152 #endif
01153     int32       typmod = PG_GETARG_INT32(2);
01154     TimeADT     result;
01155 
01156 #ifdef HAVE_INT64_TIMESTAMP
01157     result = pq_getmsgint64(buf);
01158 
01159     if (result < INT64CONST(0) || result > USECS_PER_DAY)
01160         ereport(ERROR,
01161                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01162                  errmsg("time out of range")));
01163 #else
01164     result = pq_getmsgfloat8(buf);
01165 
01166     if (result < 0 || result > (double) SECS_PER_DAY)
01167         ereport(ERROR,
01168                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01169                  errmsg("time out of range")));
01170 #endif
01171 
01172     AdjustTimeForTypmod(&result, typmod);
01173 
01174     PG_RETURN_TIMEADT(result);
01175 }
01176 
01177 /*
01178  *      time_send           - converts time to binary format
01179  */
01180 Datum
01181 time_send(PG_FUNCTION_ARGS)
01182 {
01183     TimeADT     time = PG_GETARG_TIMEADT(0);
01184     StringInfoData buf;
01185 
01186     pq_begintypsend(&buf);
01187 #ifdef HAVE_INT64_TIMESTAMP
01188     pq_sendint64(&buf, time);
01189 #else
01190     pq_sendfloat8(&buf, time);
01191 #endif
01192     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01193 }
01194 
01195 Datum
01196 timetypmodin(PG_FUNCTION_ARGS)
01197 {
01198     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
01199 
01200     PG_RETURN_INT32(anytime_typmodin(false, ta));
01201 }
01202 
01203 Datum
01204 timetypmodout(PG_FUNCTION_ARGS)
01205 {
01206     int32       typmod = PG_GETARG_INT32(0);
01207 
01208     PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
01209 }
01210 
01211 
01212 /* time_transform()
01213  * Flatten calls to time_scale() and timetz_scale() that solely represent
01214  * increases in allowed precision.
01215  */
01216 Datum
01217 time_transform(PG_FUNCTION_ARGS)
01218 {
01219     PG_RETURN_POINTER(TemporalTransform(MAX_TIME_PRECISION,
01220                                         (Node *) PG_GETARG_POINTER(0)));
01221 }
01222 
01223 /* time_scale()
01224  * Adjust time type for specified scale factor.
01225  * Used by PostgreSQL type system to stuff columns.
01226  */
01227 Datum
01228 time_scale(PG_FUNCTION_ARGS)
01229 {
01230     TimeADT     time = PG_GETARG_TIMEADT(0);
01231     int32       typmod = PG_GETARG_INT32(1);
01232     TimeADT     result;
01233 
01234     result = time;
01235     AdjustTimeForTypmod(&result, typmod);
01236 
01237     PG_RETURN_TIMEADT(result);
01238 }
01239 
01240 /* AdjustTimeForTypmod()
01241  * Force the precision of the time value to a specified value.
01242  * Uses *exactly* the same code as in AdjustTimestampForTypemod()
01243  * but we make a separate copy because those types do not
01244  * have a fundamental tie together but rather a coincidence of
01245  * implementation. - thomas
01246  */
01247 static void
01248 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
01249 {
01250 #ifdef HAVE_INT64_TIMESTAMP
01251     static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
01252         INT64CONST(1000000),
01253         INT64CONST(100000),
01254         INT64CONST(10000),
01255         INT64CONST(1000),
01256         INT64CONST(100),
01257         INT64CONST(10),
01258         INT64CONST(1)
01259     };
01260 
01261     static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
01262         INT64CONST(500000),
01263         INT64CONST(50000),
01264         INT64CONST(5000),
01265         INT64CONST(500),
01266         INT64CONST(50),
01267         INT64CONST(5),
01268         INT64CONST(0)
01269     };
01270 #else
01271     /* note MAX_TIME_PRECISION differs in this case */
01272     static const double TimeScales[MAX_TIME_PRECISION + 1] = {
01273         1.0,
01274         10.0,
01275         100.0,
01276         1000.0,
01277         10000.0,
01278         100000.0,
01279         1000000.0,
01280         10000000.0,
01281         100000000.0,
01282         1000000000.0,
01283         10000000000.0
01284     };
01285 #endif
01286 
01287     if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
01288     {
01289         /*
01290          * Note: this round-to-nearest code is not completely consistent about
01291          * rounding values that are exactly halfway between integral values.
01292          * On most platforms, rint() will implement round-to-nearest-even, but
01293          * the integer code always rounds up (away from zero).  Is it worth
01294          * trying to be consistent?
01295          */
01296 #ifdef HAVE_INT64_TIMESTAMP
01297         if (*time >= INT64CONST(0))
01298             *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
01299                 TimeScales[typmod];
01300         else
01301             *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
01302                       TimeScales[typmod]);
01303 #else
01304         *time = rint((double) *time * TimeScales[typmod]) / TimeScales[typmod];
01305 #endif
01306     }
01307 }
01308 
01309 
01310 Datum
01311 time_eq(PG_FUNCTION_ARGS)
01312 {
01313     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01314     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01315 
01316     PG_RETURN_BOOL(time1 == time2);
01317 }
01318 
01319 Datum
01320 time_ne(PG_FUNCTION_ARGS)
01321 {
01322     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01323     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01324 
01325     PG_RETURN_BOOL(time1 != time2);
01326 }
01327 
01328 Datum
01329 time_lt(PG_FUNCTION_ARGS)
01330 {
01331     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01332     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01333 
01334     PG_RETURN_BOOL(time1 < time2);
01335 }
01336 
01337 Datum
01338 time_le(PG_FUNCTION_ARGS)
01339 {
01340     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01341     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01342 
01343     PG_RETURN_BOOL(time1 <= time2);
01344 }
01345 
01346 Datum
01347 time_gt(PG_FUNCTION_ARGS)
01348 {
01349     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01350     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01351 
01352     PG_RETURN_BOOL(time1 > time2);
01353 }
01354 
01355 Datum
01356 time_ge(PG_FUNCTION_ARGS)
01357 {
01358     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01359     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01360 
01361     PG_RETURN_BOOL(time1 >= time2);
01362 }
01363 
01364 Datum
01365 time_cmp(PG_FUNCTION_ARGS)
01366 {
01367     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01368     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01369 
01370     if (time1 < time2)
01371         PG_RETURN_INT32(-1);
01372     if (time1 > time2)
01373         PG_RETURN_INT32(1);
01374     PG_RETURN_INT32(0);
01375 }
01376 
01377 Datum
01378 time_hash(PG_FUNCTION_ARGS)
01379 {
01380     /* We can use either hashint8 or hashfloat8 directly */
01381 #ifdef HAVE_INT64_TIMESTAMP
01382     return hashint8(fcinfo);
01383 #else
01384     return hashfloat8(fcinfo);
01385 #endif
01386 }
01387 
01388 Datum
01389 time_larger(PG_FUNCTION_ARGS)
01390 {
01391     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01392     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01393 
01394     PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
01395 }
01396 
01397 Datum
01398 time_smaller(PG_FUNCTION_ARGS)
01399 {
01400     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01401     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01402 
01403     PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
01404 }
01405 
01406 /* overlaps_time() --- implements the SQL OVERLAPS operator.
01407  *
01408  * Algorithm is per SQL spec.  This is much harder than you'd think
01409  * because the spec requires us to deliver a non-null answer in some cases
01410  * where some of the inputs are null.
01411  */
01412 Datum
01413 overlaps_time(PG_FUNCTION_ARGS)
01414 {
01415     /*
01416      * The arguments are TimeADT, but we leave them as generic Datums to avoid
01417      * dereferencing nulls (TimeADT is pass-by-reference!)
01418      */
01419     Datum       ts1 = PG_GETARG_DATUM(0);
01420     Datum       te1 = PG_GETARG_DATUM(1);
01421     Datum       ts2 = PG_GETARG_DATUM(2);
01422     Datum       te2 = PG_GETARG_DATUM(3);
01423     bool        ts1IsNull = PG_ARGISNULL(0);
01424     bool        te1IsNull = PG_ARGISNULL(1);
01425     bool        ts2IsNull = PG_ARGISNULL(2);
01426     bool        te2IsNull = PG_ARGISNULL(3);
01427 
01428 #define TIMEADT_GT(t1,t2) \
01429     (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
01430 #define TIMEADT_LT(t1,t2) \
01431     (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
01432 
01433     /*
01434      * If both endpoints of interval 1 are null, the result is null (unknown).
01435      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
01436      * take ts1 as the lesser endpoint.
01437      */
01438     if (ts1IsNull)
01439     {
01440         if (te1IsNull)
01441             PG_RETURN_NULL();
01442         /* swap null for non-null */
01443         ts1 = te1;
01444         te1IsNull = true;
01445     }
01446     else if (!te1IsNull)
01447     {
01448         if (TIMEADT_GT(ts1, te1))
01449         {
01450             Datum       tt = ts1;
01451 
01452             ts1 = te1;
01453             te1 = tt;
01454         }
01455     }
01456 
01457     /* Likewise for interval 2. */
01458     if (ts2IsNull)
01459     {
01460         if (te2IsNull)
01461             PG_RETURN_NULL();
01462         /* swap null for non-null */
01463         ts2 = te2;
01464         te2IsNull = true;
01465     }
01466     else if (!te2IsNull)
01467     {
01468         if (TIMEADT_GT(ts2, te2))
01469         {
01470             Datum       tt = ts2;
01471 
01472             ts2 = te2;
01473             te2 = tt;
01474         }
01475     }
01476 
01477     /*
01478      * At this point neither ts1 nor ts2 is null, so we can consider three
01479      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
01480      */
01481     if (TIMEADT_GT(ts1, ts2))
01482     {
01483         /*
01484          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
01485          * in the presence of nulls it's not quite completely so.
01486          */
01487         if (te2IsNull)
01488             PG_RETURN_NULL();
01489         if (TIMEADT_LT(ts1, te2))
01490             PG_RETURN_BOOL(true);
01491         if (te1IsNull)
01492             PG_RETURN_NULL();
01493 
01494         /*
01495          * If te1 is not null then we had ts1 <= te1 above, and we just found
01496          * ts1 >= te2, hence te1 >= te2.
01497          */
01498         PG_RETURN_BOOL(false);
01499     }
01500     else if (TIMEADT_LT(ts1, ts2))
01501     {
01502         /* This case is ts2 < te1 OR te2 < te1 */
01503         if (te1IsNull)
01504             PG_RETURN_NULL();
01505         if (TIMEADT_LT(ts2, te1))
01506             PG_RETURN_BOOL(true);
01507         if (te2IsNull)
01508             PG_RETURN_NULL();
01509 
01510         /*
01511          * If te2 is not null then we had ts2 <= te2 above, and we just found
01512          * ts2 >= te1, hence te2 >= te1.
01513          */
01514         PG_RETURN_BOOL(false);
01515     }
01516     else
01517     {
01518         /*
01519          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
01520          * rather silly way of saying "true if both are nonnull, else null".
01521          */
01522         if (te1IsNull || te2IsNull)
01523             PG_RETURN_NULL();
01524         PG_RETURN_BOOL(true);
01525     }
01526 
01527 #undef TIMEADT_GT
01528 #undef TIMEADT_LT
01529 }
01530 
01531 /* timestamp_time()
01532  * Convert timestamp to time data type.
01533  */
01534 Datum
01535 timestamp_time(PG_FUNCTION_ARGS)
01536 {
01537     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
01538     TimeADT     result;
01539     struct pg_tm tt,
01540                *tm = &tt;
01541     fsec_t      fsec;
01542 
01543     if (TIMESTAMP_NOT_FINITE(timestamp))
01544         PG_RETURN_NULL();
01545 
01546     if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
01547         ereport(ERROR,
01548                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01549                  errmsg("timestamp out of range")));
01550 
01551 #ifdef HAVE_INT64_TIMESTAMP
01552 
01553     /*
01554      * Could also do this with time = (timestamp / USECS_PER_DAY *
01555      * USECS_PER_DAY) - timestamp;
01556      */
01557     result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
01558               USECS_PER_SEC) + fsec;
01559 #else
01560     result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
01561 #endif
01562 
01563     PG_RETURN_TIMEADT(result);
01564 }
01565 
01566 /* timestamptz_time()
01567  * Convert timestamptz to time data type.
01568  */
01569 Datum
01570 timestamptz_time(PG_FUNCTION_ARGS)
01571 {
01572     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
01573     TimeADT     result;
01574     struct pg_tm tt,
01575                *tm = &tt;
01576     int         tz;
01577     fsec_t      fsec;
01578 
01579     if (TIMESTAMP_NOT_FINITE(timestamp))
01580         PG_RETURN_NULL();
01581 
01582     if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
01583         ereport(ERROR,
01584                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01585                  errmsg("timestamp out of range")));
01586 
01587 #ifdef HAVE_INT64_TIMESTAMP
01588 
01589     /*
01590      * Could also do this with time = (timestamp / USECS_PER_DAY *
01591      * USECS_PER_DAY) - timestamp;
01592      */
01593     result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
01594               USECS_PER_SEC) + fsec;
01595 #else
01596     result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
01597 #endif
01598 
01599     PG_RETURN_TIMEADT(result);
01600 }
01601 
01602 /* datetime_timestamp()
01603  * Convert date and time to timestamp data type.
01604  */
01605 Datum
01606 datetime_timestamp(PG_FUNCTION_ARGS)
01607 {
01608     DateADT     date = PG_GETARG_DATEADT(0);
01609     TimeADT     time = PG_GETARG_TIMEADT(1);
01610     Timestamp   result;
01611 
01612     result = date2timestamp(date);
01613     if (!TIMESTAMP_NOT_FINITE(result))
01614         result += time;
01615 
01616     PG_RETURN_TIMESTAMP(result);
01617 }
01618 
01619 /* time_interval()
01620  * Convert time to interval data type.
01621  */
01622 Datum
01623 time_interval(PG_FUNCTION_ARGS)
01624 {
01625     TimeADT     time = PG_GETARG_TIMEADT(0);
01626     Interval   *result;
01627 
01628     result = (Interval *) palloc(sizeof(Interval));
01629 
01630     result->time = time;
01631     result->day = 0;
01632     result->month = 0;
01633 
01634     PG_RETURN_INTERVAL_P(result);
01635 }
01636 
01637 /* interval_time()
01638  * Convert interval to time data type.
01639  *
01640  * This is defined as producing the fractional-day portion of the interval.
01641  * Therefore, we can just ignore the months field.  It is not real clear
01642  * what to do with negative intervals, but we choose to subtract the floor,
01643  * so that, say, '-2 hours' becomes '22:00:00'.
01644  */
01645 Datum
01646 interval_time(PG_FUNCTION_ARGS)
01647 {
01648     Interval   *span = PG_GETARG_INTERVAL_P(0);
01649     TimeADT     result;
01650 
01651 #ifdef HAVE_INT64_TIMESTAMP
01652     int64       days;
01653 
01654     result = span->time;
01655     if (result >= USECS_PER_DAY)
01656     {
01657         days = result / USECS_PER_DAY;
01658         result -= days * USECS_PER_DAY;
01659     }
01660     else if (result < 0)
01661     {
01662         days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
01663         result += days * USECS_PER_DAY;
01664     }
01665 #else
01666     result = span->time;
01667     if (result >= (double) SECS_PER_DAY || result < 0)
01668         result -= floor(result / (double) SECS_PER_DAY) * (double) SECS_PER_DAY;
01669 #endif
01670 
01671     PG_RETURN_TIMEADT(result);
01672 }
01673 
01674 /* time_mi_time()
01675  * Subtract two times to produce an interval.
01676  */
01677 Datum
01678 time_mi_time(PG_FUNCTION_ARGS)
01679 {
01680     TimeADT     time1 = PG_GETARG_TIMEADT(0);
01681     TimeADT     time2 = PG_GETARG_TIMEADT(1);
01682     Interval   *result;
01683 
01684     result = (Interval *) palloc(sizeof(Interval));
01685 
01686     result->month = 0;
01687     result->day = 0;
01688     result->time = time1 - time2;
01689 
01690     PG_RETURN_INTERVAL_P(result);
01691 }
01692 
01693 /* time_pl_interval()
01694  * Add interval to time.
01695  */
01696 Datum
01697 time_pl_interval(PG_FUNCTION_ARGS)
01698 {
01699     TimeADT     time = PG_GETARG_TIMEADT(0);
01700     Interval   *span = PG_GETARG_INTERVAL_P(1);
01701     TimeADT     result;
01702 
01703 #ifdef HAVE_INT64_TIMESTAMP
01704     result = time + span->time;
01705     result -= result / USECS_PER_DAY * USECS_PER_DAY;
01706     if (result < INT64CONST(0))
01707         result += USECS_PER_DAY;
01708 #else
01709     TimeADT     time1;
01710 
01711     result = time + span->time;
01712     TMODULO(result, time1, (double) SECS_PER_DAY);
01713     if (result < 0)
01714         result += SECS_PER_DAY;
01715 #endif
01716 
01717     PG_RETURN_TIMEADT(result);
01718 }
01719 
01720 /* time_mi_interval()
01721  * Subtract interval from time.
01722  */
01723 Datum
01724 time_mi_interval(PG_FUNCTION_ARGS)
01725 {
01726     TimeADT     time = PG_GETARG_TIMEADT(0);
01727     Interval   *span = PG_GETARG_INTERVAL_P(1);
01728     TimeADT     result;
01729 
01730 #ifdef HAVE_INT64_TIMESTAMP
01731     result = time - span->time;
01732     result -= result / USECS_PER_DAY * USECS_PER_DAY;
01733     if (result < INT64CONST(0))
01734         result += USECS_PER_DAY;
01735 #else
01736     TimeADT     time1;
01737 
01738     result = time - span->time;
01739     TMODULO(result, time1, (double) SECS_PER_DAY);
01740     if (result < 0)
01741         result += SECS_PER_DAY;
01742 #endif
01743 
01744     PG_RETURN_TIMEADT(result);
01745 }
01746 
01747 
01748 /* time_part()
01749  * Extract specified field from time type.
01750  */
01751 Datum
01752 time_part(PG_FUNCTION_ARGS)
01753 {
01754     text       *units = PG_GETARG_TEXT_PP(0);
01755     TimeADT     time = PG_GETARG_TIMEADT(1);
01756     float8      result;
01757     int         type,
01758                 val;
01759     char       *lowunits;
01760 
01761     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
01762                                             VARSIZE_ANY_EXHDR(units),
01763                                             false);
01764 
01765     type = DecodeUnits(0, lowunits, &val);
01766     if (type == UNKNOWN_FIELD)
01767         type = DecodeSpecial(0, lowunits, &val);
01768 
01769     if (type == UNITS)
01770     {
01771         fsec_t      fsec;
01772         struct pg_tm tt,
01773                    *tm = &tt;
01774 
01775         time2tm(time, tm, &fsec);
01776 
01777         switch (val)
01778         {
01779             case DTK_MICROSEC:
01780 #ifdef HAVE_INT64_TIMESTAMP
01781                 result = tm->tm_sec * 1000000.0 + fsec;
01782 #else
01783                 result = (tm->tm_sec + fsec) * 1000000;
01784 #endif
01785                 break;
01786 
01787             case DTK_MILLISEC:
01788 #ifdef HAVE_INT64_TIMESTAMP
01789                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
01790 #else
01791                 result = (tm->tm_sec + fsec) * 1000;
01792 #endif
01793                 break;
01794 
01795             case DTK_SECOND:
01796 #ifdef HAVE_INT64_TIMESTAMP
01797                 result = tm->tm_sec + fsec / 1000000.0;
01798 #else
01799                 result = tm->tm_sec + fsec;
01800 #endif
01801                 break;
01802 
01803             case DTK_MINUTE:
01804                 result = tm->tm_min;
01805                 break;
01806 
01807             case DTK_HOUR:
01808                 result = tm->tm_hour;
01809                 break;
01810 
01811             case DTK_TZ:
01812             case DTK_TZ_MINUTE:
01813             case DTK_TZ_HOUR:
01814             case DTK_DAY:
01815             case DTK_MONTH:
01816             case DTK_QUARTER:
01817             case DTK_YEAR:
01818             case DTK_DECADE:
01819             case DTK_CENTURY:
01820             case DTK_MILLENNIUM:
01821             case DTK_ISOYEAR:
01822             default:
01823                 ereport(ERROR,
01824                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01825                          errmsg("\"time\" units \"%s\" not recognized",
01826                                 lowunits)));
01827                 result = 0;
01828         }
01829     }
01830     else if (type == RESERV && val == DTK_EPOCH)
01831     {
01832 #ifdef HAVE_INT64_TIMESTAMP
01833         result = time / 1000000.0;
01834 #else
01835         result = time;
01836 #endif
01837     }
01838     else
01839     {
01840         ereport(ERROR,
01841                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01842                  errmsg("\"time\" units \"%s\" not recognized",
01843                         lowunits)));
01844         result = 0;
01845     }
01846 
01847     PG_RETURN_FLOAT8(result);
01848 }
01849 
01850 
01851 /*****************************************************************************
01852  *   Time With Time Zone ADT
01853  *****************************************************************************/
01854 
01855 /* tm2timetz()
01856  * Convert a tm structure to a time data type.
01857  */
01858 static int
01859 tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
01860 {
01861 #ifdef HAVE_INT64_TIMESTAMP
01862     result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
01863                     USECS_PER_SEC) + fsec;
01864 #else
01865     result->time = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
01866 #endif
01867     result->zone = tz;
01868 
01869     return 0;
01870 }
01871 
01872 Datum
01873 timetz_in(PG_FUNCTION_ARGS)
01874 {
01875     char       *str = PG_GETARG_CSTRING(0);
01876 
01877 #ifdef NOT_USED
01878     Oid         typelem = PG_GETARG_OID(1);
01879 #endif
01880     int32       typmod = PG_GETARG_INT32(2);
01881     TimeTzADT  *result;
01882     fsec_t      fsec;
01883     struct pg_tm tt,
01884                *tm = &tt;
01885     int         tz;
01886     int         nf;
01887     int         dterr;
01888     char        workbuf[MAXDATELEN + 1];
01889     char       *field[MAXDATEFIELDS];
01890     int         dtype;
01891     int         ftype[MAXDATEFIELDS];
01892 
01893     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
01894                           field, ftype, MAXDATEFIELDS, &nf);
01895     if (dterr == 0)
01896         dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
01897     if (dterr != 0)
01898         DateTimeParseError(dterr, str, "time with time zone");
01899 
01900     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
01901     tm2timetz(tm, fsec, tz, result);
01902     AdjustTimeForTypmod(&(result->time), typmod);
01903 
01904     PG_RETURN_TIMETZADT_P(result);
01905 }
01906 
01907 Datum
01908 timetz_out(PG_FUNCTION_ARGS)
01909 {
01910     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
01911     char       *result;
01912     struct pg_tm tt,
01913                *tm = &tt;
01914     fsec_t      fsec;
01915     int         tz;
01916     char        buf[MAXDATELEN + 1];
01917 
01918     timetz2tm(time, tm, &fsec, &tz);
01919     EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
01920 
01921     result = pstrdup(buf);
01922     PG_RETURN_CSTRING(result);
01923 }
01924 
01925 /*
01926  *      timetz_recv         - converts external binary format to timetz
01927  */
01928 Datum
01929 timetz_recv(PG_FUNCTION_ARGS)
01930 {
01931     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
01932 
01933 #ifdef NOT_USED
01934     Oid         typelem = PG_GETARG_OID(1);
01935 #endif
01936     int32       typmod = PG_GETARG_INT32(2);
01937     TimeTzADT  *result;
01938 
01939     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
01940 
01941 #ifdef HAVE_INT64_TIMESTAMP
01942     result->time = pq_getmsgint64(buf);
01943 
01944     if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
01945         ereport(ERROR,
01946                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01947                  errmsg("time out of range")));
01948 #else
01949     result->time = pq_getmsgfloat8(buf);
01950 
01951     if (result->time < 0 || result->time > (double) SECS_PER_DAY)
01952         ereport(ERROR,
01953                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
01954                  errmsg("time out of range")));
01955 #endif
01956 
01957     result->zone = pq_getmsgint(buf, sizeof(result->zone));
01958 
01959     /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
01960     if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
01961         ereport(ERROR,
01962                 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
01963                  errmsg("time zone displacement out of range")));
01964 
01965     AdjustTimeForTypmod(&(result->time), typmod);
01966 
01967     PG_RETURN_TIMETZADT_P(result);
01968 }
01969 
01970 /*
01971  *      timetz_send         - converts timetz to binary format
01972  */
01973 Datum
01974 timetz_send(PG_FUNCTION_ARGS)
01975 {
01976     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
01977     StringInfoData buf;
01978 
01979     pq_begintypsend(&buf);
01980 #ifdef HAVE_INT64_TIMESTAMP
01981     pq_sendint64(&buf, time->time);
01982 #else
01983     pq_sendfloat8(&buf, time->time);
01984 #endif
01985     pq_sendint(&buf, time->zone, sizeof(time->zone));
01986     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01987 }
01988 
01989 Datum
01990 timetztypmodin(PG_FUNCTION_ARGS)
01991 {
01992     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
01993 
01994     PG_RETURN_INT32(anytime_typmodin(true, ta));
01995 }
01996 
01997 Datum
01998 timetztypmodout(PG_FUNCTION_ARGS)
01999 {
02000     int32       typmod = PG_GETARG_INT32(0);
02001 
02002     PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
02003 }
02004 
02005 
02006 /* timetz2tm()
02007  * Convert TIME WITH TIME ZONE data type to POSIX time structure.
02008  */
02009 static int
02010 timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp)
02011 {
02012     TimeOffset  trem = time->time;
02013 
02014 #ifdef HAVE_INT64_TIMESTAMP
02015     tm->tm_hour = trem / USECS_PER_HOUR;
02016     trem -= tm->tm_hour * USECS_PER_HOUR;
02017     tm->tm_min = trem / USECS_PER_MINUTE;
02018     trem -= tm->tm_min * USECS_PER_MINUTE;
02019     tm->tm_sec = trem / USECS_PER_SEC;
02020     *fsec = trem - tm->tm_sec * USECS_PER_SEC;
02021 #else
02022 recalc:
02023     TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
02024     TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
02025     TMODULO(trem, tm->tm_sec, 1.0);
02026     trem = TIMEROUND(trem);
02027     /* roundoff may need to propagate to higher-order fields */
02028     if (trem >= 1.0)
02029     {
02030         trem = ceil(time->time);
02031         goto recalc;
02032     }
02033     *fsec = trem;
02034 #endif
02035 
02036     if (tzp != NULL)
02037         *tzp = time->zone;
02038 
02039     return 0;
02040 }
02041 
02042 /* timetz_scale()
02043  * Adjust time type for specified scale factor.
02044  * Used by PostgreSQL type system to stuff columns.
02045  */
02046 Datum
02047 timetz_scale(PG_FUNCTION_ARGS)
02048 {
02049     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
02050     int32       typmod = PG_GETARG_INT32(1);
02051     TimeTzADT  *result;
02052 
02053     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02054 
02055     result->time = time->time;
02056     result->zone = time->zone;
02057 
02058     AdjustTimeForTypmod(&(result->time), typmod);
02059 
02060     PG_RETURN_TIMETZADT_P(result);
02061 }
02062 
02063 
02064 static int
02065 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
02066 {
02067     TimeOffset  t1,
02068                 t2;
02069 
02070     /* Primary sort is by true (GMT-equivalent) time */
02071 #ifdef HAVE_INT64_TIMESTAMP
02072     t1 = time1->time + (time1->zone * USECS_PER_SEC);
02073     t2 = time2->time + (time2->zone * USECS_PER_SEC);
02074 #else
02075     t1 = time1->time + time1->zone;
02076     t2 = time2->time + time2->zone;
02077 #endif
02078 
02079     if (t1 > t2)
02080         return 1;
02081     if (t1 < t2)
02082         return -1;
02083 
02084     /*
02085      * If same GMT time, sort by timezone; we only want to say that two
02086      * timetz's are equal if both the time and zone parts are equal.
02087      */
02088     if (time1->zone > time2->zone)
02089         return 1;
02090     if (time1->zone < time2->zone)
02091         return -1;
02092 
02093     return 0;
02094 }
02095 
02096 Datum
02097 timetz_eq(PG_FUNCTION_ARGS)
02098 {
02099     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02100     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02101 
02102     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
02103 }
02104 
02105 Datum
02106 timetz_ne(PG_FUNCTION_ARGS)
02107 {
02108     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02109     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02110 
02111     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
02112 }
02113 
02114 Datum
02115 timetz_lt(PG_FUNCTION_ARGS)
02116 {
02117     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02118     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02119 
02120     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
02121 }
02122 
02123 Datum
02124 timetz_le(PG_FUNCTION_ARGS)
02125 {
02126     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02127     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02128 
02129     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
02130 }
02131 
02132 Datum
02133 timetz_gt(PG_FUNCTION_ARGS)
02134 {
02135     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02136     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02137 
02138     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
02139 }
02140 
02141 Datum
02142 timetz_ge(PG_FUNCTION_ARGS)
02143 {
02144     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02145     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02146 
02147     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
02148 }
02149 
02150 Datum
02151 timetz_cmp(PG_FUNCTION_ARGS)
02152 {
02153     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02154     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02155 
02156     PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
02157 }
02158 
02159 Datum
02160 timetz_hash(PG_FUNCTION_ARGS)
02161 {
02162     TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
02163     uint32      thash;
02164 
02165     /*
02166      * To avoid any problems with padding bytes in the struct, we figure the
02167      * field hashes separately and XOR them.  This also provides a convenient
02168      * framework for dealing with the fact that the time field might be either
02169      * double or int64.
02170      */
02171 #ifdef HAVE_INT64_TIMESTAMP
02172     thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
02173                                                Int64GetDatumFast(key->time)));
02174 #else
02175     thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
02176                                              Float8GetDatumFast(key->time)));
02177 #endif
02178     thash ^= DatumGetUInt32(hash_uint32(key->zone));
02179     PG_RETURN_UINT32(thash);
02180 }
02181 
02182 Datum
02183 timetz_larger(PG_FUNCTION_ARGS)
02184 {
02185     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02186     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02187     TimeTzADT  *result;
02188 
02189     if (timetz_cmp_internal(time1, time2) > 0)
02190         result = time1;
02191     else
02192         result = time2;
02193     PG_RETURN_TIMETZADT_P(result);
02194 }
02195 
02196 Datum
02197 timetz_smaller(PG_FUNCTION_ARGS)
02198 {
02199     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
02200     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
02201     TimeTzADT  *result;
02202 
02203     if (timetz_cmp_internal(time1, time2) < 0)
02204         result = time1;
02205     else
02206         result = time2;
02207     PG_RETURN_TIMETZADT_P(result);
02208 }
02209 
02210 /* timetz_pl_interval()
02211  * Add interval to timetz.
02212  */
02213 Datum
02214 timetz_pl_interval(PG_FUNCTION_ARGS)
02215 {
02216     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
02217     Interval   *span = PG_GETARG_INTERVAL_P(1);
02218     TimeTzADT  *result;
02219 
02220 #ifndef HAVE_INT64_TIMESTAMP
02221     TimeTzADT   time1;
02222 #endif
02223 
02224     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02225 
02226 #ifdef HAVE_INT64_TIMESTAMP
02227     result->time = time->time + span->time;
02228     result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
02229     if (result->time < INT64CONST(0))
02230         result->time += USECS_PER_DAY;
02231 #else
02232     result->time = time->time + span->time;
02233     TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
02234     if (result->time < 0)
02235         result->time += SECS_PER_DAY;
02236 #endif
02237 
02238     result->zone = time->zone;
02239 
02240     PG_RETURN_TIMETZADT_P(result);
02241 }
02242 
02243 /* timetz_mi_interval()
02244  * Subtract interval from timetz.
02245  */
02246 Datum
02247 timetz_mi_interval(PG_FUNCTION_ARGS)
02248 {
02249     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
02250     Interval   *span = PG_GETARG_INTERVAL_P(1);
02251     TimeTzADT  *result;
02252 
02253 #ifndef HAVE_INT64_TIMESTAMP
02254     TimeTzADT   time1;
02255 #endif
02256 
02257     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02258 
02259 #ifdef HAVE_INT64_TIMESTAMP
02260     result->time = time->time - span->time;
02261     result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
02262     if (result->time < INT64CONST(0))
02263         result->time += USECS_PER_DAY;
02264 #else
02265     result->time = time->time - span->time;
02266     TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
02267     if (result->time < 0)
02268         result->time += SECS_PER_DAY;
02269 #endif
02270 
02271     result->zone = time->zone;
02272 
02273     PG_RETURN_TIMETZADT_P(result);
02274 }
02275 
02276 /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
02277  *
02278  * Algorithm is per SQL spec.  This is much harder than you'd think
02279  * because the spec requires us to deliver a non-null answer in some cases
02280  * where some of the inputs are null.
02281  */
02282 Datum
02283 overlaps_timetz(PG_FUNCTION_ARGS)
02284 {
02285     /*
02286      * The arguments are TimeTzADT *, but we leave them as generic Datums for
02287      * convenience of notation --- and to avoid dereferencing nulls.
02288      */
02289     Datum       ts1 = PG_GETARG_DATUM(0);
02290     Datum       te1 = PG_GETARG_DATUM(1);
02291     Datum       ts2 = PG_GETARG_DATUM(2);
02292     Datum       te2 = PG_GETARG_DATUM(3);
02293     bool        ts1IsNull = PG_ARGISNULL(0);
02294     bool        te1IsNull = PG_ARGISNULL(1);
02295     bool        ts2IsNull = PG_ARGISNULL(2);
02296     bool        te2IsNull = PG_ARGISNULL(3);
02297 
02298 #define TIMETZ_GT(t1,t2) \
02299     DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
02300 #define TIMETZ_LT(t1,t2) \
02301     DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
02302 
02303     /*
02304      * If both endpoints of interval 1 are null, the result is null (unknown).
02305      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
02306      * take ts1 as the lesser endpoint.
02307      */
02308     if (ts1IsNull)
02309     {
02310         if (te1IsNull)
02311             PG_RETURN_NULL();
02312         /* swap null for non-null */
02313         ts1 = te1;
02314         te1IsNull = true;
02315     }
02316     else if (!te1IsNull)
02317     {
02318         if (TIMETZ_GT(ts1, te1))
02319         {
02320             Datum       tt = ts1;
02321 
02322             ts1 = te1;
02323             te1 = tt;
02324         }
02325     }
02326 
02327     /* Likewise for interval 2. */
02328     if (ts2IsNull)
02329     {
02330         if (te2IsNull)
02331             PG_RETURN_NULL();
02332         /* swap null for non-null */
02333         ts2 = te2;
02334         te2IsNull = true;
02335     }
02336     else if (!te2IsNull)
02337     {
02338         if (TIMETZ_GT(ts2, te2))
02339         {
02340             Datum       tt = ts2;
02341 
02342             ts2 = te2;
02343             te2 = tt;
02344         }
02345     }
02346 
02347     /*
02348      * At this point neither ts1 nor ts2 is null, so we can consider three
02349      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
02350      */
02351     if (TIMETZ_GT(ts1, ts2))
02352     {
02353         /*
02354          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
02355          * in the presence of nulls it's not quite completely so.
02356          */
02357         if (te2IsNull)
02358             PG_RETURN_NULL();
02359         if (TIMETZ_LT(ts1, te2))
02360             PG_RETURN_BOOL(true);
02361         if (te1IsNull)
02362             PG_RETURN_NULL();
02363 
02364         /*
02365          * If te1 is not null then we had ts1 <= te1 above, and we just found
02366          * ts1 >= te2, hence te1 >= te2.
02367          */
02368         PG_RETURN_BOOL(false);
02369     }
02370     else if (TIMETZ_LT(ts1, ts2))
02371     {
02372         /* This case is ts2 < te1 OR te2 < te1 */
02373         if (te1IsNull)
02374             PG_RETURN_NULL();
02375         if (TIMETZ_LT(ts2, te1))
02376             PG_RETURN_BOOL(true);
02377         if (te2IsNull)
02378             PG_RETURN_NULL();
02379 
02380         /*
02381          * If te2 is not null then we had ts2 <= te2 above, and we just found
02382          * ts2 >= te1, hence te2 >= te1.
02383          */
02384         PG_RETURN_BOOL(false);
02385     }
02386     else
02387     {
02388         /*
02389          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
02390          * rather silly way of saying "true if both are nonnull, else null".
02391          */
02392         if (te1IsNull || te2IsNull)
02393             PG_RETURN_NULL();
02394         PG_RETURN_BOOL(true);
02395     }
02396 
02397 #undef TIMETZ_GT
02398 #undef TIMETZ_LT
02399 }
02400 
02401 
02402 Datum
02403 timetz_time(PG_FUNCTION_ARGS)
02404 {
02405     TimeTzADT  *timetz = PG_GETARG_TIMETZADT_P(0);
02406     TimeADT     result;
02407 
02408     /* swallow the time zone and just return the time */
02409     result = timetz->time;
02410 
02411     PG_RETURN_TIMEADT(result);
02412 }
02413 
02414 
02415 Datum
02416 time_timetz(PG_FUNCTION_ARGS)
02417 {
02418     TimeADT     time = PG_GETARG_TIMEADT(0);
02419     TimeTzADT  *result;
02420     struct pg_tm tt,
02421                *tm = &tt;
02422     fsec_t      fsec;
02423     int         tz;
02424 
02425     GetCurrentDateTime(tm);
02426     time2tm(time, tm, &fsec);
02427     tz = DetermineTimeZoneOffset(tm, session_timezone);
02428 
02429     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02430 
02431     result->time = time;
02432     result->zone = tz;
02433 
02434     PG_RETURN_TIMETZADT_P(result);
02435 }
02436 
02437 
02438 /* timestamptz_timetz()
02439  * Convert timestamp to timetz data type.
02440  */
02441 Datum
02442 timestamptz_timetz(PG_FUNCTION_ARGS)
02443 {
02444     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
02445     TimeTzADT  *result;
02446     struct pg_tm tt,
02447                *tm = &tt;
02448     int         tz;
02449     fsec_t      fsec;
02450 
02451     if (TIMESTAMP_NOT_FINITE(timestamp))
02452         PG_RETURN_NULL();
02453 
02454     if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
02455         ereport(ERROR,
02456                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02457                  errmsg("timestamp out of range")));
02458 
02459     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02460 
02461     tm2timetz(tm, fsec, tz, result);
02462 
02463     PG_RETURN_TIMETZADT_P(result);
02464 }
02465 
02466 
02467 /* datetimetz_timestamptz()
02468  * Convert date and timetz to timestamp with time zone data type.
02469  * Timestamp is stored in GMT, so add the time zone
02470  * stored with the timetz to the result.
02471  * - thomas 2000-03-10
02472  */
02473 Datum
02474 datetimetz_timestamptz(PG_FUNCTION_ARGS)
02475 {
02476     DateADT     date = PG_GETARG_DATEADT(0);
02477     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
02478     TimestampTz result;
02479 
02480     if (DATE_IS_NOBEGIN(date))
02481         TIMESTAMP_NOBEGIN(result);
02482     else if (DATE_IS_NOEND(date))
02483         TIMESTAMP_NOEND(result);
02484     else
02485     {
02486 #ifdef HAVE_INT64_TIMESTAMP
02487         result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
02488 #else
02489         result = date * (double) SECS_PER_DAY + time->time + time->zone;
02490 #endif
02491     }
02492 
02493     PG_RETURN_TIMESTAMP(result);
02494 }
02495 
02496 
02497 /* timetz_part()
02498  * Extract specified field from time type.
02499  */
02500 Datum
02501 timetz_part(PG_FUNCTION_ARGS)
02502 {
02503     text       *units = PG_GETARG_TEXT_PP(0);
02504     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
02505     float8      result;
02506     int         type,
02507                 val;
02508     char       *lowunits;
02509 
02510     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
02511                                             VARSIZE_ANY_EXHDR(units),
02512                                             false);
02513 
02514     type = DecodeUnits(0, lowunits, &val);
02515     if (type == UNKNOWN_FIELD)
02516         type = DecodeSpecial(0, lowunits, &val);
02517 
02518     if (type == UNITS)
02519     {
02520         double      dummy;
02521         int         tz;
02522         fsec_t      fsec;
02523         struct pg_tm tt,
02524                    *tm = &tt;
02525 
02526         timetz2tm(time, tm, &fsec, &tz);
02527 
02528         switch (val)
02529         {
02530             case DTK_TZ:
02531                 result = -tz;
02532                 break;
02533 
02534             case DTK_TZ_MINUTE:
02535                 result = -tz;
02536                 result /= SECS_PER_MINUTE;
02537                 FMODULO(result, dummy, (double) SECS_PER_MINUTE);
02538                 break;
02539 
02540             case DTK_TZ_HOUR:
02541                 dummy = -tz;
02542                 FMODULO(dummy, result, (double) SECS_PER_HOUR);
02543                 break;
02544 
02545             case DTK_MICROSEC:
02546 #ifdef HAVE_INT64_TIMESTAMP
02547                 result = tm->tm_sec * 1000000.0 + fsec;
02548 #else
02549                 result = (tm->tm_sec + fsec) * 1000000;
02550 #endif
02551                 break;
02552 
02553             case DTK_MILLISEC:
02554 #ifdef HAVE_INT64_TIMESTAMP
02555                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
02556 #else
02557                 result = (tm->tm_sec + fsec) * 1000;
02558 #endif
02559                 break;
02560 
02561             case DTK_SECOND:
02562 #ifdef HAVE_INT64_TIMESTAMP
02563                 result = tm->tm_sec + fsec / 1000000.0;
02564 #else
02565                 result = tm->tm_sec + fsec;
02566 #endif
02567                 break;
02568 
02569             case DTK_MINUTE:
02570                 result = tm->tm_min;
02571                 break;
02572 
02573             case DTK_HOUR:
02574                 result = tm->tm_hour;
02575                 break;
02576 
02577             case DTK_DAY:
02578             case DTK_MONTH:
02579             case DTK_QUARTER:
02580             case DTK_YEAR:
02581             case DTK_DECADE:
02582             case DTK_CENTURY:
02583             case DTK_MILLENNIUM:
02584             default:
02585                 ereport(ERROR,
02586                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02587                 errmsg("\"time with time zone\" units \"%s\" not recognized",
02588                        lowunits)));
02589                 result = 0;
02590         }
02591     }
02592     else if (type == RESERV && val == DTK_EPOCH)
02593     {
02594 #ifdef HAVE_INT64_TIMESTAMP
02595         result = time->time / 1000000.0 + time->zone;
02596 #else
02597         result = time->time + time->zone;
02598 #endif
02599     }
02600     else
02601     {
02602         ereport(ERROR,
02603                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02604                  errmsg("\"time with time zone\" units \"%s\" not recognized",
02605                         lowunits)));
02606         result = 0;
02607     }
02608 
02609     PG_RETURN_FLOAT8(result);
02610 }
02611 
02612 /* timetz_zone()
02613  * Encode time with time zone type with specified time zone.
02614  * Applies DST rules as of the current date.
02615  */
02616 Datum
02617 timetz_zone(PG_FUNCTION_ARGS)
02618 {
02619     text       *zone = PG_GETARG_TEXT_PP(0);
02620     TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
02621     TimeTzADT  *result;
02622     int         tz;
02623     char        tzname[TZ_STRLEN_MAX + 1];
02624     char       *lowzone;
02625     int         type,
02626                 val;
02627     pg_tz      *tzp;
02628 
02629     /*
02630      * Look up the requested timezone.  First we look in the date token table
02631      * (to handle cases like "EST"), and if that fails, we look in the
02632      * timezone database (to handle cases like "America/New_York").  (This
02633      * matches the order in which timestamp input checks the cases; it's
02634      * important because the timezone database unwisely uses a few zone names
02635      * that are identical to offset abbreviations.)
02636      */
02637     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
02638     lowzone = downcase_truncate_identifier(tzname,
02639                                            strlen(tzname),
02640                                            false);
02641 
02642     type = DecodeSpecial(0, lowzone, &val);
02643 
02644     if (type == TZ || type == DTZ)
02645         tz = val * MINS_PER_HOUR;
02646     else
02647     {
02648         tzp = pg_tzset(tzname);
02649         if (tzp)
02650         {
02651             /* Get the offset-from-GMT that is valid today for the zone */
02652             pg_time_t   now = (pg_time_t) time(NULL);
02653             struct pg_tm *tm;
02654 
02655             tm = pg_localtime(&now, tzp);
02656             tz = -tm->tm_gmtoff;
02657         }
02658         else
02659         {
02660             ereport(ERROR,
02661                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02662                      errmsg("time zone \"%s\" not recognized", tzname)));
02663             tz = 0;             /* keep compiler quiet */
02664         }
02665     }
02666 
02667     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02668 
02669 #ifdef HAVE_INT64_TIMESTAMP
02670     result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
02671     while (result->time < INT64CONST(0))
02672         result->time += USECS_PER_DAY;
02673     while (result->time >= USECS_PER_DAY)
02674         result->time -= USECS_PER_DAY;
02675 #else
02676     result->time = t->time + (t->zone - tz);
02677     while (result->time < 0)
02678         result->time += SECS_PER_DAY;
02679     while (result->time >= SECS_PER_DAY)
02680         result->time -= SECS_PER_DAY;
02681 #endif
02682 
02683     result->zone = tz;
02684 
02685     PG_RETURN_TIMETZADT_P(result);
02686 }
02687 
02688 /* timetz_izone()
02689  * Encode time with time zone type with specified time interval as time zone.
02690  */
02691 Datum
02692 timetz_izone(PG_FUNCTION_ARGS)
02693 {
02694     Interval   *zone = PG_GETARG_INTERVAL_P(0);
02695     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
02696     TimeTzADT  *result;
02697     int         tz;
02698 
02699     if (zone->month != 0 || zone->day != 0)
02700         ereport(ERROR,
02701                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02702                  errmsg("interval time zone \"%s\" must not include months or days",
02703                         DatumGetCString(DirectFunctionCall1(interval_out,
02704                                                   PointerGetDatum(zone))))));
02705 
02706 #ifdef HAVE_INT64_TIMESTAMP
02707     tz = -(zone->time / USECS_PER_SEC);
02708 #else
02709     tz = -(zone->time);
02710 #endif
02711 
02712     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
02713 
02714 #ifdef HAVE_INT64_TIMESTAMP
02715     result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
02716     while (result->time < INT64CONST(0))
02717         result->time += USECS_PER_DAY;
02718     while (result->time >= USECS_PER_DAY)
02719         result->time -= USECS_PER_DAY;
02720 #else
02721     result->time = time->time + (time->zone - tz);
02722     while (result->time < 0)
02723         result->time += SECS_PER_DAY;
02724     while (result->time >= SECS_PER_DAY)
02725         result->time -= SECS_PER_DAY;
02726 #endif
02727 
02728     result->zone = tz;
02729 
02730     PG_RETURN_TIMETZADT_P(result);
02731 }