diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0da02fd896..4babad9524 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.142 2000/02/15 03:26:38 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.143 2000/02/16 17:24:36 thomas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -5180,6 +5180,7 @@ ColId: IDENT { $$ = $1; } | INITIALLY { $$ = "initially"; } | INSENSITIVE { $$ = "insensitive"; } | INSTEAD { $$ = "instead"; } + | INTERVAL { $$ = "interval"; } | ISNULL { $$ = "isnull"; } | ISOLATION { $$ = "isolation"; } | KEY { $$ = "key"; } @@ -5456,8 +5457,10 @@ xlateSqlType(char *name) return "numeric"; else if (!strcasecmp(name, "char")) return "bpchar"; - else if (!strcasecmp(name, "interval")) - return "timespan"; + else if (!strcasecmp(name, "datetime")) + return "timestamp"; + else if (!strcasecmp(name, "timespan")) + return "interval"; else if (!strcasecmp(name, "boolean")) return "bool"; else diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 67a3413238..7fa7b01688 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.29 2000/01/26 05:56:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.30 2000/02/16 17:24:37 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -293,18 +293,18 @@ TypeCategory(Oid inType) case (INT8OID): case (FLOAT4OID): case (FLOAT8OID): + case (NUMERICOID): case (CASHOID): result = NUMERIC_TYPE; break; case (ABSTIMEOID): case (TIMESTAMPOID): - case (DATETIMEOID): result = DATETIME_TYPE; break; case (RELTIMEOID): - case (TIMESPANOID): + case (INTERVALOID): result = TIMESPAN_TYPE; break; @@ -362,16 +362,18 @@ PreferredType(CATEGORY category, Oid type) case (NUMERIC_TYPE): if (type == OIDOID) result = OIDOID; + else if (type == NUMERICOID) + result = NUMERICOID; else result = FLOAT8OID; break; case (DATETIME_TYPE): - result = DATETIMEOID; + result = TIMESTAMPOID; break; case (TIMESPAN_TYPE): - result = TIMESPANOID; + result = INTERVALOID; break; case (NETWORK_TYPE): @@ -419,22 +421,25 @@ PromoteTypeToNext(Oid inType) result = FLOAT8OID; break; + case (NUMERICOID): + result = NUMERICOID; + break; + case (DATEOID): case (ABSTIMEOID): - case (TIMESTAMPOID): - result = DATETIMEOID; + result = TIMESTAMPOID; break; case (TIMEOID): case (RELTIMEOID): - result = TIMESPANOID; + result = INTERVALOID; break; case (BOOLOID): case (TEXTOID): case (FLOAT8OID): - case (DATETIMEOID): - case (TIMESPANOID): + case (TIMESTAMPOID): + case (INTERVALOID): default: result = inType; break; diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 192928db09..030ca95178 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -4,7 +4,7 @@ # Makefile for utils/adt # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.33 2000/01/25 23:53:51 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.34 2000/02/16 17:24:46 thomas Exp $ # #------------------------------------------------------------------------- @@ -24,7 +24,7 @@ endif endif OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o chunk.o \ - date.o datetime.o datum.o dt.o filename.o float.o \ + date.o datetime.o datum.o filename.o float.o \ geo_ops.o geo_selfuncs.o int.o int8.o like.o \ misc.o nabstime.o name.o not_in.o numeric.o numutils.o \ oid.o oracle_compat.o \ diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c deleted file mode 100644 index 90a5c5c9db..0000000000 --- a/src/backend/utils/adt/dt.c +++ /dev/null @@ -1,4270 +0,0 @@ -/*------------------------------------------------------------------------- - * - * dt.c - * Functions for the built-in type "dt". - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.83 2000/02/15 03:17:09 thomas Exp $ - * - *------------------------------------------------------------------------- - */ -#include -#include -#include -#include - -#include "postgres.h" -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifndef USE_POSIX_TIME -#include -#endif - -#include "miscadmin.h" -#include "utils/builtins.h" - -static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); -static int DecodeNumber(int flen, char *field, - int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); -static int DecodeNumberField(int len, char *str, - int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); -static int DecodeSpecial(int field, char *lowtoken, int *val); -static int DecodeTime(char *str, int fmask, int *tmask, - struct tm * tm, double *fsec); -static int DecodeTimezone(char *str, int *tzp); -static int DecodeUnits(int field, char *lowtoken, int *val); -static int EncodeSpecialDateTime(DateTime dt, char *str); -static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); -static DateTime dt2local(DateTime dt, int timezone); -static void dt2time(DateTime dt, int *hour, int *min, double *sec); -static int j2day(int jd); -static double time2t(const int hour, const int min, const double sec); -static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec); -static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span); - - -#define USE_DATE_CACHE 1 -#define ROUND_ALL 0 - -int day_tab[2][13] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, -{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}; - - -char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", -"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; - -char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", -"Thursday", "Friday", "Saturday", NULL}; - -/* TMODULO() - * Macro to replace modf(), which is broken on some platforms. - */ -#define TMODULO(t,q,u) \ -do { \ - q = ((t < 0)? ceil(t / u): floor(t / u)); \ - if (q != 0) \ - t -= rint(q * u); \ -} while(0) - -static void GetEpochTime(struct tm * tm); - -#define UTIME_MINYEAR (1901) -#define UTIME_MINMONTH (12) -#define UTIME_MINDAY (14) -#define UTIME_MAXYEAR (2038) -#define UTIME_MAXMONTH (01) -#define UTIME_MAXDAY (18) - -#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ - || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ - || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ - && ((y < UTIME_MAXYEAR) \ - || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ - || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) - - -/***************************************************************************** - * USER I/O ROUTINES * - *****************************************************************************/ - -/* datetime_in() - * Convert a string to internal form. - */ -DateTime * -datetime_in(char *str) -{ - DateTime *result; - - double fsec; - struct tm tt, - *tm = &tt; - int tz; - int dtype; - int nf; - char *field[MAXDATEFIELDS]; - int ftype[MAXDATEFIELDS]; - char lowstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) datetime external representation"); - - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) - elog(ERROR, "Bad datetime external representation '%s'", str); - - result = palloc(sizeof(DateTime)); - - switch (dtype) - { - case DTK_DATE: - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "Datetime out of range '%s'", str); - break; - - case DTK_EPOCH: - DATETIME_EPOCH(*result); - break; - - case DTK_CURRENT: - DATETIME_CURRENT(*result); - break; - - case DTK_LATE: - DATETIME_NOEND(*result); - break; - - case DTK_EARLY: - DATETIME_NOBEGIN(*result); - break; - - case DTK_INVALID: - DATETIME_INVALID(*result); - break; - - default: - elog(ERROR, "Internal coding error, can't input datetime '%s'", str); - } - - return result; -} /* datetime_in() */ - -/* datetime_out() - * Convert a datetime to external form. - */ -char * -datetime_out(DateTime *dt) -{ - char *result; - int tz; - struct tm tt, - *tm = &tt; - double fsec; - char *tzn; - char buf[MAXDATELEN + 1]; - - if (!PointerIsValid(dt)) - return NULL; - - if (DATETIME_IS_RESERVED(*dt)) - { - EncodeSpecialDateTime(*dt, buf); - - } - else if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) == 0) - { - EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); - - } - else - EncodeSpecialDateTime(DT_INVALID, buf); - - result = palloc(strlen(buf) + 1); - - strcpy(result, buf); - - return result; -} /* datetime_out() */ - - -/* timespan_in() - * Convert a string to internal form. - * - * External format(s): - * Uses the generic date/time parsing and decoding routines. - */ -TimeSpan * -timespan_in(char *str) -{ - TimeSpan *span; - - double fsec; - struct tm tt, - *tm = &tt; - int dtype; - int nf; - char *field[MAXDATEFIELDS]; - int ftype[MAXDATEFIELDS]; - char lowstr[MAXDATELEN + 1]; - - tm->tm_year = 0; - tm->tm_mon = 0; - tm->tm_mday = 0; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - fsec = 0; - - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) timespan external representation"); - - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) - elog(ERROR, "Bad timespan external representation '%s'", str); - - span = palloc(sizeof(TimeSpan)); - - switch (dtype) - { - case DTK_DELTA: - if (tm2timespan(tm, fsec, span) != 0) - { -#if NOT_USED - TIMESPAN_INVALID(span); -#endif - elog(ERROR, "Bad timespan external representation '%s'", str); - } - break; - - default: - elog(ERROR, "Internal coding error, can't input timespan '%s'", str); - } - - return span; -} /* timespan_in() */ - -/* timespan_out() - * Convert a time span to external form. - */ -char * -timespan_out(TimeSpan *span) -{ - char *result; - - struct tm tt, - *tm = &tt; - double fsec; - char buf[MAXDATELEN + 1]; - - if (!PointerIsValid(span)) - return NULL; - - if (timespan2tm(*span, tm, &fsec) != 0) - return NULL; - - if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0) - elog(ERROR, "Unable to format timespan"); - - result = palloc(strlen(buf) + 1); - - strcpy(result, buf); - return result; -} /* timespan_out() */ - - -/***************************************************************************** - * PUBLIC ROUTINES * - *****************************************************************************/ - - -bool -datetime_finite(DateTime *datetime) -{ - if (!PointerIsValid(datetime)) - return FALSE; - - return !DATETIME_NOT_FINITE(*datetime); -} /* datetime_finite() */ - -bool -timespan_finite(TimeSpan *timespan) -{ - if (!PointerIsValid(timespan)) - return FALSE; - - return !TIMESPAN_NOT_FINITE(*timespan); -} /* timespan_finite() */ - - -/*---------------------------------------------------------- - * Relational operators for datetime. - *---------------------------------------------------------*/ - -static void -GetEpochTime(struct tm * tm) -{ - struct tm *t0; - time_t epoch = 0; - - t0 = gmtime(&epoch); - - tm->tm_year = t0->tm_year; - tm->tm_mon = t0->tm_mon; - tm->tm_mday = t0->tm_mday; - tm->tm_hour = t0->tm_hour; - tm->tm_min = t0->tm_min; - tm->tm_sec = t0->tm_sec; - - if (tm->tm_year < 1900) - tm->tm_year += 1900; - tm->tm_mon++; - - return; -} /* GetEpochTime() */ - -DateTime -SetDateTime(DateTime dt) -{ - struct tm tt; - - if (DATETIME_IS_CURRENT(dt)) - { - GetCurrentTime(&tt); - tm2datetime(&tt, 0, NULL, &dt); - dt = dt2local(dt, -CTimeZone); - } - else - { /* if (DATETIME_IS_EPOCH(dt1)) */ - GetEpochTime(&tt); - tm2datetime(&tt, 0, NULL, &dt); - } - - return dt; -} /* SetDateTime() */ - -/* datetime_relop - is datetime1 relop datetime2 - */ -bool -datetime_eq(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 == dt2; -} /* datetime_eq() */ - -bool -datetime_ne(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 != dt2; -} /* datetime_ne() */ - -bool -datetime_lt(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 < dt2; -} /* datetime_lt() */ - -bool -datetime_gt(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 > dt2; -} /* datetime_gt() */ - -bool -datetime_le(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 <= dt2; -} /* datetime_le() */ - -bool -datetime_ge(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 >= dt2; -} /* datetime_ge() */ - - -/* datetime_cmp - 3-state comparison for datetime - * collate invalid datetime at the end - */ -int -datetime_cmp(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return 0; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1)) - { - return (DATETIME_IS_INVALID(dt2) ? 0 : 1); - - } - else if (DATETIME_IS_INVALID(dt2)) - { - return -1; - - } - else - { - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - } - - return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0)); -} /* datetime_cmp() */ - - -/* timespan_relop - is timespan1 relop timespan2 - */ -bool -timespan_eq(TimeSpan *timespan1, TimeSpan *timespan2) -{ - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - return ((timespan1->time == timespan2->time) - && (timespan1->month == timespan2->month)); -} /* timespan_eq() */ - -bool -timespan_ne(TimeSpan *timespan1, TimeSpan *timespan2) -{ - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - return ((timespan1->time != timespan2->time) - || (timespan1->month != timespan2->month)); -} /* timespan_ne() */ - -bool -timespan_lt(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 < span2; -} /* timespan_lt() */ - -bool -timespan_gt(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 > span2; -} /* timespan_gt() */ - -bool -timespan_le(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 <= span2; -} /* timespan_le() */ - -bool -timespan_ge(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 >= span2; -} /* timespan_ge() */ - - -/* timespan_cmp - 3-state comparison for timespan - */ -int -timespan_cmp(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return 0; - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - return TIMESPAN_IS_INVALID(*timespan2) ? 0 : 1; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - return -1; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return (span1 < span2) ? -1 : (span1 > span2) ? 1 : 0; -} /* timespan_cmp() */ - - -/*---------------------------------------------------------- - * "Arithmetic" operators on date/times. - * datetime_foo returns foo as an object (pointer) that - * can be passed between languages. - * datetime_xx is an internal routine which returns the - * actual value. - *---------------------------------------------------------*/ - -DateTime * -datetime_smaller(DateTime *datetime1, DateTime *datetime2) -{ - DateTime *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1)) - *result = dt2; - else if (DATETIME_IS_INVALID(dt2)) - *result = dt1; - else - *result = ((dt2 < dt1) ? dt2 : dt1); - - return result; -} /* datetime_smaller() */ - -DateTime * -datetime_larger(DateTime *datetime1, DateTime *datetime2) -{ - DateTime *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1)) - *result = dt2; - else if (DATETIME_IS_INVALID(dt2)) - *result = dt1; - else - *result = ((dt2 > dt1) ? dt2 : dt1); - - return result; -} /* datetime_larger() */ - - -TimeSpan * -datetime_mi(DateTime *datetime1, DateTime *datetime2) -{ - TimeSpan *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(TimeSpan)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1) - || DATETIME_IS_INVALID(dt2)) - { - DATETIME_INVALID(result->time); - - } - else - result->time = JROUND(dt1 - dt2); - result->month = 0; - - return result; -} /* datetime_mi() */ - - -/* datetime_pl_span() - * Add a timespan to a datetime data type. - * Note that timespan has provisions for qualitative year/month - * units, so try to do the right thing with them. - * To add a month, increment the month, and use the same day of month. - * Then, if the next month has fewer days, set the day of month - * to the last day of month. - * Lastly, add in the "quantitative time". - */ -DateTime * -datetime_pl_span(DateTime *datetime, TimeSpan *span) -{ - DateTime *result; - DateTime dt; - int tz; - char *tzn; - - if ((!PointerIsValid(datetime)) || (!PointerIsValid(span))) - return NULL; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_NOT_FINITE(*datetime)) - { - *result = *datetime; - - } - else if (TIMESPAN_IS_INVALID(*span)) - { - DATETIME_INVALID(*result); - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if (span->month != 0) - { - struct tm tt, - *tm = &tt; - double fsec; - - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0) - { - tm->tm_mon += span->month; - if (tm->tm_mon > 12) - { - tm->tm_year += ((tm->tm_mon - 1) / 12); - tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); - } - else if (tm->tm_mon < 1) - { - tm->tm_year += ((tm->tm_mon / 12) - 1); - tm->tm_mon = ((tm->tm_mon % 12) + 12); - } - - /* adjust for end of month boundary problems... */ - if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) - tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); - - if (tm2datetime(tm, fsec, &tz, &dt) != 0) - elog(ERROR, "Unable to add datetime and timespan"); - - } - else - DATETIME_INVALID(dt); - } - -#ifdef ROUND_ALL - dt = JROUND(dt + span->time); -#else - dt += span->time; -#endif - - *result = dt; - } - - return result; -} /* datetime_pl_span() */ - -DateTime * -datetime_mi_span(DateTime *datetime, TimeSpan *span) -{ - DateTime *result; - TimeSpan tspan; - - if (!PointerIsValid(datetime) || !PointerIsValid(span)) - return NULL; - - tspan.month = -span->month; - tspan.time = -span->time; - - result = datetime_pl_span(datetime, &tspan); - - return result; -} /* datetime_mi_span() */ - - -TimeSpan * -timespan_um(TimeSpan *timespan) -{ - TimeSpan *result; - - if (!PointerIsValid(timespan)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->time = -(timespan->time); - result->month = -(timespan->month); - - return result; -} /* timespan_um() */ - - -TimeSpan * -timespan_smaller(TimeSpan *timespan1, TimeSpan *timespan2) -{ - TimeSpan *result; - - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - { - result->time = timespan1->time; - result->month = timespan1->month; - - } - else - { - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - if (span2 < span1) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else - { - result->time = timespan1->time; - result->month = timespan1->month; - } - } - - return result; -} /* timespan_smaller() */ - -TimeSpan * -timespan_larger(TimeSpan *timespan1, TimeSpan *timespan2) -{ - TimeSpan *result; - - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - { - result->time = timespan1->time; - result->month = timespan1->month; - - } - else - { - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - if (span2 > span1) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else - { - result->time = timespan1->time; - result->month = timespan1->month; - } - } - - return result; -} /* timespan_larger() */ - - -TimeSpan * -timespan_pl(TimeSpan *span1, TimeSpan *span2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->month = (span1->month + span2->month); - result->time = JROUND(span1->time + span2->time); - - return result; -} /* timespan_pl() */ - -TimeSpan * -timespan_mi(TimeSpan *span1, TimeSpan *span2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->month = (span1->month - span2->month); - result->time = JROUND(span1->time - span2->time); - - return result; -} /* timespan_mi() */ - -TimeSpan * -timespan_div(TimeSpan *span1, float8 *arg2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2))) - return NULL; - - if (!PointerIsValid(result = palloc(sizeof(TimeSpan)))) - elog(ERROR, "Memory allocation failed, can't divide timespans"); - - if (*arg2 == 0.0) - elog(ERROR, "timespan_div: divide by 0.0 error"); - - result->month = rint(span1->month / *arg2); - result->time = JROUND(span1->time / *arg2); - - return result; -} /* timespan_div() */ - -/* datetime_age() - * Calculate time difference while retaining year/month fields. - * Note that this does not result in an accurate absolute time span - * since year and month are out of context once the arithmetic - * is done. - */ -TimeSpan * -datetime_age(DateTime *datetime1, DateTime *datetime2) -{ - TimeSpan *result; - - DateTime dt1, - dt2; - double fsec, - fsec1, - fsec2; - struct tm tt, - *tm = &tt; - struct tm tt1, - *tm1 = &tt1; - struct tm tt2, - *tm2 = &tt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1) - || DATETIME_IS_INVALID(dt2)) - { - DATETIME_INVALID(result->time); - - } - else if ((datetime2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) - && (datetime2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) - { - fsec = (fsec1 - fsec2); - tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); - tm->tm_min = (tm1->tm_min - tm2->tm_min); - tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); - tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); - tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); - tm->tm_year = (tm1->tm_year - tm2->tm_year); - - /* flip sign if necessary... */ - if (dt1 < dt2) - { - fsec = -fsec; - tm->tm_sec = -tm->tm_sec; - tm->tm_min = -tm->tm_min; - tm->tm_hour = -tm->tm_hour; - tm->tm_mday = -tm->tm_mday; - tm->tm_mon = -tm->tm_mon; - tm->tm_year = -tm->tm_year; - } - - if (tm->tm_sec < 0) - { - tm->tm_sec += 60; - tm->tm_min--; - } - - if (tm->tm_min < 0) - { - tm->tm_min += 60; - tm->tm_hour--; - } - - if (tm->tm_hour < 0) - { - tm->tm_hour += 24; - tm->tm_mday--; - } - - if (tm->tm_mday < 0) - { - if (dt1 < dt2) - { - tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1]; - tm->tm_mon--; - } - else - { - tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1]; - tm->tm_mon--; - } - } - - if (tm->tm_mon < 0) - { - tm->tm_mon += 12; - tm->tm_year--; - } - - /* recover sign if necessary... */ - if (dt1 < dt2) - { - fsec = -fsec; - tm->tm_sec = -tm->tm_sec; - tm->tm_min = -tm->tm_min; - tm->tm_hour = -tm->tm_hour; - tm->tm_mday = -tm->tm_mday; - tm->tm_mon = -tm->tm_mon; - tm->tm_year = -tm->tm_year; - } - - if (tm2timespan(tm, fsec, result) != 0) - elog(ERROR, "Unable to decode datetime"); - - } - else - elog(ERROR, "Unable to decode datetime"); - - return result; -} /* datetime_age() */ - - -/*---------------------------------------------------------- - * Conversion operators. - *---------------------------------------------------------*/ - - -/* datetime_text() - * Convert datetime to text data type. - */ -text * -datetime_text(DateTime *datetime) -{ - text *result; - char *str; - int len; - - if (!PointerIsValid(datetime)) - return NULL; - - str = datetime_out(datetime); - - if (!PointerIsValid(str)) - return NULL; - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - return result; -} /* datetime_text() */ - - -/* text_datetime() - * Convert text string to datetime. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -DateTime * -text_datetime(text *str) -{ - DateTime *result; - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - return NULL; - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - result = datetime_in(dstr); - - return result; -} /* text_datetime() */ - - -/* timespan_text() - * Convert timespan to text data type. - */ -text * -timespan_text(TimeSpan *timespan) -{ - text *result; - char *str; - int len; - - if (!PointerIsValid(timespan)) - return NULL; - - str = timespan_out(timespan); - - if (!PointerIsValid(str)) - return NULL; - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - return result; -} /* timespan_text() */ - - -/* text_timespan() - * Convert text string to timespan. - * Text type may not be null terminated, so copy to temporary string - * then call the standard input routine. - */ -TimeSpan * -text_timespan(text *str) -{ - TimeSpan *result; - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - return NULL; - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - result = timespan_in(dstr); - - return result; -} /* text_timespan() */ - -/* datetime_trunc() - * Extract specified field from datetime. - */ -DateTime * -datetime_trunc(text *units, DateTime *datetime) -{ - DateTime *result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - char *tzn; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(datetime))) - return NULL; - - result = palloc(sizeof(DateTime)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { -#if NOT_USED -/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ - elog(ERROR, "Datetime is not finite", NULL); -#endif - *result = 0; - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)) - { - switch (val) - { - case DTK_MILLENIUM: - tm->tm_year = (tm->tm_year / 1000) * 1000; - case DTK_CENTURY: - tm->tm_year = (tm->tm_year / 100) * 100; - case DTK_DECADE: - tm->tm_year = (tm->tm_year / 10) * 10; - case DTK_YEAR: - tm->tm_mon = 1; - case DTK_QUARTER: - tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1; - case DTK_MONTH: - tm->tm_mday = 1; - case DTK_DAY: - tm->tm_hour = 0; - case DTK_HOUR: - tm->tm_min = 0; - case DTK_MINUTE: - tm->tm_sec = 0; - case DTK_SECOND: - fsec = 0; - break; - - case DTK_MILLISEC: - fsec = rint(fsec * 1000) / 1000; - break; - - case DTK_MICROSEC: - fsec = rint(fsec * 1000000) / 1000000; - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - result = NULL; - } - - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { -#ifdef USE_POSIX_TIME - tm->tm_isdst = -1; - tm->tm_year -= 1900; - tm->tm_mon -= 1; - tm->tm_isdst = -1; - mktime(tm); - tm->tm_year += 1900; - tm->tm_mon += 1; - -#if defined(HAVE_TM_ZONE) - tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ -#elif defined(HAVE_INT_TIMEZONE) - -#ifdef __CYGWIN__ - tz = (tm->tm_isdst ? (_timezone - 3600) : _timezone); -#else - tz = (tm->tm_isdst ? (timezone - 3600) : timezone); -#endif - -#else -#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined -#endif - -#else /* !USE_POSIX_TIME */ - tz = CTimeZone; -#endif - } - else - { - tm->tm_isdst = 0; - tz = 0; - } - - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "Unable to truncate datetime to '%s'", lowunits); - -#if NOT_USED - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - DATETIME_EPOCH(*result); - *result = dt - SetDateTime(*result); -#endif - - } - else - { - elog(ERROR, "Datetime units '%s' not recognized", lowunits); - result = NULL; - } - } - - return result; -} /* datetime_trunc() */ - -/* timespan_trunc() - * Extract specified field from timespan. - */ -TimeSpan * -timespan_trunc(text *units, TimeSpan *timespan) -{ - TimeSpan *result; - - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(timespan))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - - if (TIMESPAN_IS_INVALID(*timespan)) - { -#if NOT_USED - elog(ERROR, "Timespan is not finite", NULL); -#endif - result = NULL; - - } - else if (type == UNITS) - { - - if (timespan2tm(*timespan, tm, &fsec) == 0) - { - switch (val) - { - case DTK_MILLENIUM: - tm->tm_year = (tm->tm_year / 1000) * 1000; - case DTK_CENTURY: - tm->tm_year = (tm->tm_year / 100) * 100; - case DTK_DECADE: - tm->tm_year = (tm->tm_year / 10) * 10; - case DTK_YEAR: - tm->tm_mon = 0; - case DTK_QUARTER: - tm->tm_mon = (3 * (tm->tm_mon / 4)); - case DTK_MONTH: - tm->tm_mday = 0; - case DTK_DAY: - tm->tm_hour = 0; - case DTK_HOUR: - tm->tm_min = 0; - case DTK_MINUTE: - tm->tm_sec = 0; - case DTK_SECOND: - fsec = 0; - break; - - case DTK_MILLISEC: - fsec = rint(fsec * 1000) / 1000; - break; - - case DTK_MICROSEC: - fsec = rint(fsec * 1000000) / 1000000; - break; - - default: - elog(ERROR, "Timespan units '%s' not supported", lowunits); - result = NULL; - } - - if (tm2timespan(tm, fsec, result) != 0) - elog(ERROR, "Unable to truncate timespan to '%s'", lowunits); - - } - else - { - elog(NOTICE, "Timespan out of range"); - result = NULL; - } - -#if NOT_USED - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - *result = timespan->time; - if (timespan->month != 0) - { - *result += ((365.25 * 86400) * (timespan->month / 12)); - *result += ((30 * 86400) * (timespan->month % 12)); - } -#endif - - } - else - { - elog(ERROR, "Timespan units '%s' not recognized", textout(units)); - result = NULL; - } - - return result; -} /* timespan_trunc() */ - - -/* datetime_part() - * Extract specified field from datetime. - */ -float64 -datetime_part(text *units, DateTime *datetime) -{ - float64 result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double dummy; - double fsec; - char *tzn; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(datetime))) - return NULL; - - result = palloc(sizeof(float64data)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - if (type == IGNORE) - type = DecodeSpecial(0, lowunits, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { -#if NOT_USED -/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ - elog(ERROR, "Datetime is not finite", NULL); -#endif - *result = 0; - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)) - { - switch (val) - { - case DTK_TZ: - *result = tz; - break; - - case DTK_TZ_MINUTE: - *result = tz / 60; - TMODULO(*result, dummy, 60e0); - break; - - case DTK_TZ_HOUR: - dummy = tz; - TMODULO(dummy, *result, 3600e0); - break; - - case DTK_MICROSEC: - *result = (fsec * 1000000); - break; - - case DTK_MILLISEC: - *result = (fsec * 1000); - break; - - case DTK_SECOND: - *result = (tm->tm_sec + fsec); - break; - - case DTK_MINUTE: - *result = tm->tm_min; - break; - - case DTK_HOUR: - *result = tm->tm_hour; - break; - - case DTK_DAY: - *result = tm->tm_mday; - break; - - case DTK_MONTH: - *result = tm->tm_mon; - break; - - case DTK_QUARTER: - *result = (tm->tm_mon / 4) + 1; - break; - - case DTK_YEAR: - *result = tm->tm_year; - break; - - case DTK_DECADE: - *result = (tm->tm_year / 10); - break; - - case DTK_CENTURY: - *result = (tm->tm_year / 100); - break; - - case DTK_MILLENIUM: - *result = (tm->tm_year / 1000); - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - *result = 0; - } - - } - else if (type == RESERV) - { - switch (val) - { - case DTK_EPOCH: - DATETIME_EPOCH(*result); - *result = dt - SetDateTime(*result); - break; - - case DTK_DOW: - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "Unable to encode datetime"); - - *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); - break; - - case DTK_DOY: - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "Unable to encode datetime"); - - *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - - date2j(tm->tm_year, 1, 1) + 1); - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - *result = 0; - } - - } - else - { - elog(ERROR, "Datetime units '%s' not recognized", lowunits); - *result = 0; - } - } - - return result; -} /* datetime_part() */ - - -/* timespan_part() - * Extract specified field from timespan. - */ -float64 -timespan_part(text *units, TimeSpan *timespan) -{ - float64 result; - - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(timespan))) - return NULL; - - result = palloc(sizeof(float64data)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - if (type == IGNORE) - type = DecodeSpecial(0, lowunits, &val); - - if (TIMESPAN_IS_INVALID(*timespan)) - { -#if NOT_USED - elog(ERROR, "Timespan is not finite"); -#endif - *result = 0; - - } - else if (type == UNITS) - { - - if (timespan2tm(*timespan, tm, &fsec) == 0) - { - switch (val) - { - case DTK_MICROSEC: - *result = (fsec * 1000000); - break; - - case DTK_MILLISEC: - *result = (fsec * 1000); - break; - - case DTK_SECOND: - *result = (tm->tm_sec + fsec); - break; - - case DTK_MINUTE: - *result = tm->tm_min; - break; - - case DTK_HOUR: - *result = tm->tm_hour; - break; - - case DTK_DAY: - *result = tm->tm_mday; - break; - - case DTK_MONTH: - *result = tm->tm_mon; - break; - - case DTK_QUARTER: - *result = (tm->tm_mon / 4) + 1; - break; - - case DTK_YEAR: - *result = tm->tm_year; - break; - - case DTK_DECADE: - *result = (tm->tm_year / 10); - break; - - case DTK_CENTURY: - *result = (tm->tm_year / 100); - break; - - case DTK_MILLENIUM: - *result = (tm->tm_year / 1000); - break; - - default: - elog(ERROR, "Timespan units '%s' not yet supported", textout(units)); - result = NULL; - } - - } - else - { - elog(NOTICE, "Timespan out of range"); - *result = 0; - } - - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - *result = timespan->time; - if (timespan->month != 0) - { - *result += ((365.25 * 86400) * (timespan->month / 12)); - *result += ((30 * 86400) * (timespan->month % 12)); - } - - } - else - { - elog(ERROR, "Timespan units '%s' not recognized", textout(units)); - *result = 0; - } - - return result; -} /* timespan_part() */ - - -/* datetime_zone() - * Encode datetime type with specified time zone. - */ -text * -datetime_zone(text *zone, DateTime *datetime) -{ - text *result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowzone[MAXDATELEN + 1]; - char *tzn, - upzone[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - char buf[MAXDATELEN + 1]; - int len; - - if ((!PointerIsValid(zone)) || (!PointerIsValid(datetime))) - return NULL; - - up = VARDATA(zone); - lp = lowzone; - for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeSpecial(0, lowzone, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { - - /* - * could return null but Postgres doesn't like that currently. - - * tgl 97/06/12 - */ - elog(ERROR, "Datetime is not finite"); - result = NULL; - - } - else if ((type == TZ) || (type == DTZ)) - { - tm->tm_isdst = ((type == DTZ) ? 1 : 0); - tz = val * 60; - - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - dt = dt2local(dt, tz); - - if (datetime2tm(dt, NULL, tm, &fsec, NULL) != 0) - elog(ERROR, "Datetime not legal"); - - up = upzone; - lp = lowzone; - for (i = 0; *lp != '\0'; i++) - *up++ = toupper(*lp++); - *up = '\0'; - - tzn = upzone; - EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); - - len = (strlen(buf) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), buf, (len - VARHDRSZ)); - - } - else - { - elog(ERROR, "Time zone '%s' not recognized", lowzone); - result = NULL; - } - - return result; -} /* datetime_zone() */ - - -/***************************************************************************** - * PRIVATE ROUTINES * - *****************************************************************************/ - -/* definitions for squeezing values into "value" */ -#define ABS_SIGNBIT (char) 0200 -#define VALMASK (char) 0177 -#define NEG(n) ((n)|ABS_SIGNBIT) -#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c)) -#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */ -#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10)) - -/* - * to keep this table reasonably small, we divide the lexval for TZ and DTZ - * entries by 10 and truncate the text field at MAXTOKLEN characters. - * the text field is not guaranteed to be NULL-terminated. - */ -static datetkn datetktbl[] = { -/* text token lexval */ - {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */ - {"acsst", DTZ, 63}, /* Cent. Australia */ - {"acst", TZ, 57}, /* Cent. Australia */ - {DA_D, ADBC, AD}, /* "ad" for years >= 0 */ - {"abstime", IGNORE, 0}, /* "abstime" for pre-v6.1 "Invalid - * Abstime" */ - {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */ - {"aesst", DTZ, 66}, /* E. Australia */ - {"aest", TZ, 60}, /* Australia Eastern Std Time */ - {"ahst", TZ, NEG(60)}, /* Alaska-Hawaii Std Time */ - {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */ - {"am", AMPM, AM}, - {"apr", MONTH, 4}, - {"april", MONTH, 4}, - {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */ - {"at", IGNORE, 0}, /* "at" (throwaway) */ - {"aug", MONTH, 8}, - {"august", MONTH, 8}, - {"awsst", DTZ, 54}, /* W. Australia */ - {"awst", TZ, 48}, /* W. Australia */ - {DB_C, ADBC, BC}, /* "bc" for years < 0 */ - {"bst", TZ, 6}, /* British Summer Time */ - {"bt", TZ, 18}, /* Baghdad Time */ - {"cadt", DTZ, 63}, /* Central Australian DST */ - {"cast", TZ, 57}, /* Central Australian ST */ - {"cat", TZ, NEG(60)}, /* Central Alaska Time */ - {"cct", TZ, 48}, /* China Coast */ - {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */ - {"cet", TZ, 6}, /* Central European Time */ - {"cetdst", DTZ, 12}, /* Central European Dayl.Time */ -#if USE_AUSTRALIAN_RULES - {"cst", TZ, 63}, /* Australia Eastern Std Time */ -#else - {"cst", TZ, NEG(36)}, /* Central Standard Time */ -#endif - {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */ - {"dec", MONTH, 12}, - {"december", MONTH, 12}, - {"dnt", TZ, 6}, /* Dansk Normal Tid */ - {"dow", RESERV, DTK_DOW}, /* day of week */ - {"doy", RESERV, DTK_DOY}, /* day of year */ - {"dst", DTZMOD, 6}, - {"east", TZ, 60}, /* East Australian Std Time */ - {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */ - {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */ - {"eetdst", DTZ, 18}, /* Eastern Europe */ - {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */ -#if USE_AUSTRALIAN_RULES - {"est", TZ, 60}, /* Australia Eastern Std Time */ -#else - {"est", TZ, NEG(30)}, /* Eastern Standard Time */ -#endif - {"feb", MONTH, 2}, - {"february", MONTH, 2}, - {"fri", DOW, 5}, - {"friday", DOW, 5}, - {"fst", TZ, 6}, /* French Summer Time */ - {"fwt", DTZ, 12}, /* French Winter Time */ - {"gmt", TZ, 0}, /* Greenwish Mean Time */ - {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */ - {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */ - {"hmt", DTZ, 18}, /* Hellas ? ? */ - {"hst", TZ, NEG(60)}, /* Hawaii Std Time */ - {"idle", TZ, 72}, /* Intl. Date Line, East */ - {"idlw", TZ, NEG(72)}, /* Intl. Date Line, West */ - {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */ - {INVALID, RESERV, DTK_INVALID}, - /* "invalid" reserved for invalid time */ - {"ist", TZ, 12}, /* Israel */ - {"it", TZ, 21}, /* Iran Time */ - {"jan", MONTH, 1}, - {"january", MONTH, 1}, - {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */ - {"jt", TZ, 45}, /* Java Time */ - {"jul", MONTH, 7}, - {"july", MONTH, 7}, - {"jun", MONTH, 6}, - {"june", MONTH, 6}, - {"kst", TZ, 54}, /* Korea Standard Time */ - {"ligt", TZ, 60}, /* From Melbourne, Australia */ - {"mar", MONTH, 3}, - {"march", MONTH, 3}, - {"may", MONTH, 5}, - {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */ - {"mest", DTZ, 12}, /* Middle Europe Summer Time */ - {"met", TZ, 6}, /* Middle Europe Time */ - {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */ - {"mewt", TZ, 6}, /* Middle Europe Winter Time */ - {"mez", TZ, 6}, /* Middle Europe Zone */ - {"mon", DOW, 1}, - {"monday", DOW, 1}, - {"mst", TZ, NEG(42)}, /* Mountain Standard Time */ - {"mt", TZ, 51}, /* Moluccas Time */ - {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */ - {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */ - {"nor", TZ, 6}, /* Norway Standard Time */ - {"nov", MONTH, 11}, - {"november", MONTH, 11}, - {NOW, RESERV, DTK_NOW}, /* current transaction time */ - {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */ - {"nt", TZ, NEG(66)}, /* Nome Time */ - {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */ - {"nzst", TZ, 72}, /* New Zealand Standard Time */ - {"nzt", TZ, 72}, /* New Zealand Time */ - {"oct", MONTH, 10}, - {"october", MONTH, 10}, - {"on", IGNORE, 0}, /* "on" (throwaway) */ - {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */ - {"pm", AMPM, PM}, - {"pst", TZ, NEG(48)}, /* Pacific Standard Time */ - {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */ - {"sast", TZ, 57}, /* South Australian Std Time */ - {"sat", DOW, 6}, - {"saturday", DOW, 6}, - {"sep", MONTH, 9}, - {"sept", MONTH, 9}, - {"september", MONTH, 9}, - {"set", TZ, NEG(6)}, /* Seychelles Time ?? */ - {"sst", DTZ, 12}, /* Swedish Summer Time */ - {"sun", DOW, 0}, - {"sunday", DOW, 0}, - {"swt", TZ, 6}, /* Swedish Winter Time */ - {"thu", DOW, 4}, - {"thur", DOW, 4}, - {"thurs", DOW, 4}, - {"thursday", DOW, 4}, - {TODAY, RESERV, DTK_TODAY}, /* midnight */ - {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */ - {"tue", DOW, 2}, - {"tues", DOW, 2}, - {"tuesday", DOW, 2}, - {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid - * time */ - {"ut", TZ, 0}, - {"utc", TZ, 0}, - {"wadt", DTZ, 48}, /* West Australian DST */ - {"wast", TZ, 42}, /* West Australian Std Time */ - {"wat", TZ, NEG(6)}, /* West Africa Time */ - {"wdt", DTZ, 54}, /* West Australian DST */ - {"wed", DOW, 3}, - {"wednesday", DOW, 3}, - {"weds", DOW, 3}, - {"wet", TZ, 0}, /* Western Europe */ - {"wetdst", DTZ, 6}, /* Western Europe */ - {"wst", TZ, 48}, /* West Australian Std Time */ - {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */ - {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */ - {"yst", TZ, NEG(54)}, /* Yukon Standard Time */ - {"zp4", TZ, NEG(24)}, /* GMT +4 hours. */ - {"zp5", TZ, NEG(30)}, /* GMT +5 hours. */ - {"zp6", TZ, NEG(36)}, /* GMT +6 hours. */ - {"z", RESERV, DTK_ZULU}, /* 00:00:00 */ - {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */ -}; - -static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]; - -static datetkn deltatktbl[] = { -/* text token lexval */ - {"@", IGNORE, 0}, /* postgres relative time prefix */ - {DAGO, AGO, 0}, /* "ago" indicates negative time offset */ - {"c", UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"cent", UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative time units */ - {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"d", UNITS, DTK_DAY}, /* "day" relative time units */ - {DDAY, UNITS, DTK_DAY}, /* "day" relative time units */ - {"days", UNITS, DTK_DAY}, /* "days" relative time units */ - {"dec", UNITS, DTK_DECADE}, /* "decade" relative time units */ - {"decs", UNITS, DTK_DECADE},/* "decades" relative time units */ - {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative time units */ - {"decades", UNITS, DTK_DECADE}, /* "decades" relative time units */ - {"h", UNITS, DTK_HOUR}, /* "hour" relative time units */ - {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative time units */ - {"hours", UNITS, DTK_HOUR}, /* "hours" relative time units */ - {"hr", UNITS, DTK_HOUR}, /* "hour" relative time units */ - {"hrs", UNITS, DTK_HOUR}, /* "hours" relative time units */ - {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid - * time */ - {"m", UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative - * time units */ - {"mil", UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */ - {"mils", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */ - {"millenia", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */ - {DMILLENIUM, UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */ - {"millisecon", UNITS, DTK_MILLISEC}, /* relative time units */ - {"min", UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */ - {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */ - {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative time units */ - {"mon", UNITS, DTK_MONTH}, /* "months" relative time units */ - {"mons", UNITS, DTK_MONTH}, /* "months" relative time units */ - {DMONTH, UNITS, DTK_MONTH}, /* "month" relative time units */ - {"months", UNITS, DTK_MONTH}, - {"ms", UNITS, DTK_MILLISEC}, - {"msec", UNITS, DTK_MILLISEC}, - {DMILLISEC, UNITS, DTK_MILLISEC}, - {"mseconds", UNITS, DTK_MILLISEC}, - {"msecs", UNITS, DTK_MILLISEC}, - {"qtr", UNITS, DTK_QUARTER},/* "quarter" relative time */ - {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative time */ - {"reltime", IGNORE, 0}, /* for pre-v6.1 "Undefined Reltime" */ - {"s", UNITS, DTK_SECOND}, - {"sec", UNITS, DTK_SECOND}, - {DSECOND, UNITS, DTK_SECOND}, - {"seconds", UNITS, DTK_SECOND}, - {"secs", UNITS, DTK_SECOND}, - {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */ - {"tz", UNITS, DTK_TZ}, /* "timezone" time offset */ - {"tz_hour", UNITS, DTK_TZ_HOUR}, /* timezone hour units */ - {"tz_minute", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */ - {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */ - {"us", UNITS, DTK_MICROSEC},/* "microsecond" relative time units */ - {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative time - * units */ - {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative time - * units */ - {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative time - * units */ - {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative time - * units */ - {"w", UNITS, DTK_WEEK}, /* "week" relative time units */ - {DWEEK, UNITS, DTK_WEEK}, /* "week" relative time units */ - {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative time units */ - {"y", UNITS, DTK_YEAR}, /* "year" relative time units */ - {DYEAR, UNITS, DTK_YEAR}, /* "year" relative time units */ - {"years", UNITS, DTK_YEAR}, /* "years" relative time units */ - {"yr", UNITS, DTK_YEAR}, /* "year" relative time units */ - {"yrs", UNITS, DTK_YEAR}, /* "years" relative time units */ -}; - -static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0]; - -#if USE_DATE_CACHE -datetkn *datecache[MAXDATEFIELDS] = {NULL}; - -datetkn *deltacache[MAXDATEFIELDS] = {NULL}; - -#endif - - -/* - * Calendar time to Julian date conversions. - * Julian date is commonly used in astronomical applications, - * since it is numerically accurate and computationally simple. - * The algorithms here will accurately convert between Julian day - * and calendar date for all non-negative Julian days - * (i.e. from Nov 23, -4713 on). - * - * Ref: Explanatory Supplement to the Astronomical Almanac, 1992. - * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941. - * - * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague - * now at Aerospace Corp. (hi, Henry!) - * - * These routines will be used by other date/time packages - tgl 97/02/25 - */ - -int -date2j(int y, int m, int d) -{ - int m12 = (m - 14) / 12; - - return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12 - - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075); -} /* date2j() */ - -void -j2date(int jd, int *year, int *month, int *day) -{ - int j, - y, - m, - d; - - int i, - l, - n; - - l = jd + 68569; - n = (4 * l) / 146097; - l -= (146097 * n + 3) / 4; - i = (4000 * (l + 1)) / 1461001; - l += 31 - (1461 * i) / 4; - j = (80 * l) / 2447; - d = l - (2447 * j) / 80; - l = j / 11; - m = (j + 2) - (12 * l); - y = 100 * (n - 49) + i + l; - - *year = y; - *month = m; - *day = d; - return; -} /* j2date() */ - -static int -j2day(int date) -{ - int day; - - day = (date + 1) % 7; - - return day; -} /* j2day() */ - - -/* datetime2tm() - * Convert datetime data type to POSIX time structure. - * Note that year is _not_ 1900-based, but is an explicit full value. - * Also, month is one-based, _not_ zero-based. - * Returns: - * 0 on success - * -1 on out of range - * - * For dates within the system-supported time_t range, convert to the - * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 - */ -int -datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn) -{ - double date, - date0, - time, - sec; - time_t utime; - -#ifdef USE_POSIX_TIME - struct tm *tx; - -#endif - - date0 = date2j(2000, 1, 1); - - time = dt; - TMODULO(time, date, 86400e0); - - if (time < 0) - { - time += 86400; - date -= 1; - } - - /* Julian day routine does not work for negative Julian days */ - if (date < -date0) - return -1; - - /* add offset to go from J2000 back to standard Julian date */ - date += date0; - - j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - dt2time(time, &tm->tm_hour, &tm->tm_min, &sec); - - *fsec = JROUND(sec); - TMODULO(*fsec, tm->tm_sec, 1e0); - - if (tzp != NULL) - { - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { - utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400); - -#ifdef USE_POSIX_TIME - tx = localtime(&utime); - tm->tm_year = tx->tm_year + 1900; - tm->tm_mon = tx->tm_mon + 1; - tm->tm_mday = tx->tm_mday; - tm->tm_hour = tx->tm_hour; - tm->tm_min = tx->tm_min; -#if NOT_USED -/* XXX HACK - * Argh! My Linux box puts in a 1 second offset for dates less than 1970 - * but only if the seconds field was non-zero. So, don't copy the seconds - * field and instead carry forward from the original - tgl 97/06/18 - * Note that GNU/Linux uses the standard freeware zic package as do - * many other platforms so this may not be GNU/Linux/ix86-specific. - */ - tm->tm_sec = tx->tm_sec; -#endif - tm->tm_isdst = tx->tm_isdst; - -#if defined(HAVE_TM_ZONE) - tm->tm_gmtoff = tx->tm_gmtoff; - tm->tm_zone = tx->tm_zone; - - *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ - if (tzn != NULL) - *tzn = (char *) tm->tm_zone; -#elif defined(HAVE_INT_TIMEZONE) -#ifdef __CYGWIN__ - *tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone); -#else - *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone); -#endif - if (tzn != NULL) - *tzn = tzname[(tm->tm_isdst > 0)]; -#else -#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined -#endif - -#else /* !USE_POSIX_TIME */ - *tzp = CTimeZone; /* V7 conventions; don't know timezone? */ - if (tzn != NULL) - *tzn = CTZName; -#endif - - } - else - { - *tzp = 0; - tm->tm_isdst = 0; - if (tzn != NULL) - *tzn = NULL; - } - - dt = dt2local(dt, *tzp); - - } - else - { - tm->tm_isdst = 0; - if (tzn != NULL) - *tzn = NULL; - } - - return 0; -} /* datetime2tm() */ - - -/* tm2datetime() - * Convert a tm structure to a datetime data type. - * Note that year is _not_ 1900-based, but is an explicit full value. - * Also, month is one-based, _not_ zero-based. - */ -int -tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime *result) -{ - - double date, - time; - - /* Julian day routines are not correct for negative Julian days */ - if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) - return -1; - - date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); - time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec)); - *result = (date * 86400 + time); - if (tzp != NULL) - *result = dt2local(*result, -(*tzp)); - - return 0; -} /* tm2datetime() */ - - -/* timespan2tm() - * Convert a timespan data type to a tm structure. - */ -static int -timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec) -{ - double time; - - if (span.month != 0) - { - tm->tm_year = span.month / 12; - tm->tm_mon = span.month % 12; - - } - else - { - tm->tm_year = 0; - tm->tm_mon = 0; - } - -#ifdef ROUND_ALL - time = JROUND(span.time); -#else - time = span.time; -#endif - - TMODULO(time, tm->tm_mday, 86400e0); - TMODULO(time, tm->tm_hour, 3600e0); - TMODULO(time, tm->tm_min, 60e0); - TMODULO(time, tm->tm_sec, 1e0); - *fsec = time; - - return 0; -} /* timespan2tm() */ - -static int -tm2timespan(struct tm * tm, double fsec, TimeSpan *span) -{ - span->month = ((tm->tm_year * 12) + tm->tm_mon); - span->time = ((((((tm->tm_mday * 24.0) - + tm->tm_hour) * 60.0) - + tm->tm_min) * 60.0) - + tm->tm_sec); - span->time = JROUND(span->time + fsec); - - return 0; -} /* tm2timespan() */ - - -static DateTime -dt2local(DateTime dt, int tz) -{ - dt -= tz; - dt = JROUND(dt); - return dt; -} /* dt2local() */ - -static double -time2t(const int hour, const int min, const double sec) -{ - return (((hour * 60) + min) * 60) + sec; -} /* time2t() */ - -static void -dt2time(DateTime jd, int *hour, int *min, double *sec) -{ - double time; - - time = jd; - - *hour = (time / 3600); - time -= ((*hour) * 3600); - *min = (time / 60); - time -= ((*min) * 60); - *sec = JROUND(time); - - return; -} /* dt2time() */ - - -/* - * parse and convert date in timestr (the normal interface) - * - * Returns the number of seconds since epoch (J2000) - */ - -/* ParseDateTime() - * Break string into tokens based on a date/time context. - */ -int -ParseDateTime(char *timestr, char *lowstr, - char **field, int *ftype, int maxfields, int *numfields) -{ - int nf = 0; - char *cp = timestr; - char *lp = lowstr; - - /* outer loop through fields */ - while (*cp != '\0') - { - field[nf] = lp; - - /* leading digit? then date or time */ - if (isdigit(*cp) || (*cp == '.')) - { - *lp++ = *cp++; - while (isdigit(*cp)) - *lp++ = *cp++; - /* time field? */ - if (*cp == ':') - { - ftype[nf] = DTK_TIME; - while (isdigit(*cp) || (*cp == ':') || (*cp == '.')) - *lp++ = *cp++; - - } - /* date field? allow embedded text month */ - else if ((*cp == '-') || (*cp == '/') || (*cp == '.')) - { - ftype[nf] = DTK_DATE; - while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.')) - *lp++ = tolower(*cp++); - - } - - /* - * otherwise, number only and will determine year, month, or - * day later - */ - else - ftype[nf] = DTK_NUMBER; - - } - - /* - * text? then date string, month, day of week, special, or - * timezone - */ - else if (isalpha(*cp)) - { - ftype[nf] = DTK_STRING; - *lp++ = tolower(*cp++); - while (isalpha(*cp)) - *lp++ = tolower(*cp++); - - /* full date string with leading text month? */ - if ((*cp == '-') || (*cp == '/') || (*cp == '.')) - { - /* - * special case of Posix timezone "GMT-0800" - * Note that other sign (e.g. "GMT+0800" - * is recognized as two separate fields and handled later. - * XXX There is no room for a delimiter between - * the "GMT" and the "-0800", so we are going to just swallow the "GMT". - * But this leads to other troubles with the definition of signs, - * so we have to flip - * - thomas 2000-02-06 - */ - if ((*cp == '-') && isdigit(*(cp+1)) - && (strncmp(field[nf], "gmt", 3) == 0)) - { - *cp = '+'; - continue; - } - - ftype[nf] = DTK_DATE; - while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.')) - *lp++ = tolower(*cp++); - } - - /* skip leading spaces */ - } - else if (isspace(*cp)) - { - cp++; - continue; - - /* sign? then special or numeric timezone */ - } - else if ((*cp == '+') || (*cp == '-')) - { - *lp++ = *cp++; - /* soak up leading whitespace */ - while (isspace(*cp)) - cp++; - /* numeric timezone? */ - if (isdigit(*cp)) - { - ftype[nf] = DTK_TZ; - *lp++ = *cp++; - while (isdigit(*cp) || (*cp == ':')) - *lp++ = *cp++; - - /* special? */ - } - else if (isalpha(*cp)) - { - ftype[nf] = DTK_SPECIAL; - *lp++ = tolower(*cp++); - while (isalpha(*cp)) - *lp++ = tolower(*cp++); - - /* otherwise something wrong... */ - } - else - return -1; - - /* ignore punctuation but use as delimiter */ - } - else if (ispunct(*cp)) - { - cp++; - continue; - - } - else - return -1; - - /* force in a delimiter */ - *lp++ = '\0'; - nf++; - if (nf > MAXDATEFIELDS) - return -1; - } - - *numfields = nf; - - return 0; -} /* ParseDateTime() */ - - -/* DecodeDateTime() - * Interpret previously parsed fields for general date and time. - * Return 0 if full date, 1 if only time, and -1 if problems. - * External format(s): - * " -- ::" - * "Fri Feb-7-1997 15:23:27" - * "Feb-7-1997 15:23:27" - * "2-7-1997 15:23:27" - * "1997-2-7 15:23:27" - * "1997.038 15:23:27" (day of year 1-366) - * Also supports input in compact time: - * "970207 152327" - * "97038 152327" - * - * Use the system-provided functions to get the current time zone - * if not specified in the input string. - * If the date is outside the time_t system-supported time range, - * then assume GMT time zone. - tgl 97/05/27 - */ -int -DecodeDateTime(char **field, int *ftype, int nf, - int *dtype, struct tm * tm, double *fsec, int *tzp) -{ - int fmask = 0, - tmask, - type; - int i; - int flen, - val; - int mer = HR24; - int haveTextMonth = FALSE; - int is2digits = FALSE; - int bc = FALSE; - - *dtype = DTK_DATE; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - *fsec = 0; - tm->tm_isdst = -1; /* don't know daylight savings time status - * apriori */ - if (tzp != NULL) - *tzp = 0; - - for (i = 0; i < nf; i++) - { - switch (ftype[i]) - { - case DTK_DATE: - if (DecodeDate(field[i], fmask, &tmask, tm) != 0) - return -1; - break; - - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - - /* - * check upper limit on hours; other limits checked in - * DecodeTime() - */ - if (tm->tm_hour > 23) - return -1; - break; - - case DTK_TZ: - if (tzp == NULL) - return -1; - if (DecodeTimezone(field[i], tzp) != 0) - return -1; - tmask = DTK_M(TZ); - break; - - case DTK_NUMBER: - flen = strlen(field[i]); - - /* - * long numeric string and either no date or no time read - * yet? then interpret as a concatenated date or time... - */ - if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M))) - { - if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - - } - /* otherwise it is a single date/time field... */ - else - { - if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - } - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = DTK_M(type); - switch (type) - { - case RESERV: - switch (val) - { - case DTK_NOW: - tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_DATE; - GetCurrentTime(tm); - if (tzp != NULL) - *tzp = CTimeZone; - break; - - case DTK_YESTERDAY: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_TODAY: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_TOMORROW: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_ZULU: - tmask = (DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_DATE; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - if (tzp != NULL) - *tzp = 0; - break; - - default: - *dtype = val; - } - - break; - - case MONTH: - /* - * already have a (numeric) month? then see if we - * can substitute... - */ - if ((fmask & DTK_M(MONTH)) && (!haveTextMonth) - && (!(fmask & DTK_M(DAY))) - && ((tm->tm_mon >= 1) && (tm->tm_mon <= 31))) - { - tm->tm_mday = tm->tm_mon; - tmask = DTK_M(DAY); - } - haveTextMonth = TRUE; - tm->tm_mon = val; - break; - - case DTZMOD: - - /* - * daylight savings time modifier (solves "MET - * DST" syntax) - */ - tmask |= DTK_M(DTZ); - tm->tm_isdst = 1; - if (tzp == NULL) - return -1; - *tzp += val * 60; - break; - - case DTZ: - - /* - * set mask for TZ here _or_ check for DTZ later - * when getting default timezone - */ - tmask |= DTK_M(TZ); - tm->tm_isdst = 1; - if (tzp == NULL) - return -1; - *tzp = val * 60; - break; - - case TZ: - tm->tm_isdst = 0; - if (tzp == NULL) - return -1; - *tzp = val * 60; - - /* Swallow an immediately succeeding timezone if this is GMT - * This handles the odd case in FreeBSD of "GMT+0800" - * but note that we need to flip the sign on this too. - * Claims to be some sort of POSIX standard format :( - * - thomas 2000-01-20 - */ - if ((i < (nf-1)) && (ftype[i+1] == DTK_TZ) - && (strcmp(field[i], "gmt") == 0)) - { - i++; - if (DecodeTimezone(field[i], tzp) != 0) - return -1; - - /* flip the sign per POSIX standard */ - *tzp = -(*tzp); - } - - - break; - - case IGNORE: - break; - - case AMPM: - mer = val; - break; - - case ADBC: - bc = (val == BC); - break; - - case DOW: - tm->tm_wday = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ - if (bc) - { - if (tm->tm_year > 0) - tm->tm_year = -(tm->tm_year - 1); - else - elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year); - } - else if (is2digits) - { - if (tm->tm_year < 70) - tm->tm_year += 2000; - else if (tm->tm_year < 100) - tm->tm_year += 1900; - } - - if ((mer != HR24) && (tm->tm_hour > 12)) - return -1; - if ((mer == AM) && (tm->tm_hour == 12)) - tm->tm_hour = 0; - else if ((mer == PM) && (tm->tm_hour != 12)) - tm->tm_hour += 12; - - /* do additional checking for full date specs... */ - if (*dtype == DTK_DATE) - { - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1; - - /* - * check for valid day of month, now that we know for sure the - * month and year... - */ - if ((tm->tm_mday < 1) - || (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])) - return -1; - - /* timezone not specified? then find local timezone if possible */ - if (((fmask & DTK_DATE_M) == DTK_DATE_M) - && (tzp != NULL) && (!(fmask & DTK_M(TZ)))) - { - - /* - * daylight savings time modifier but no standard timezone? - * then error - */ - if (fmask & DTK_M(DTZMOD)) - return -1; - - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { -#ifdef USE_POSIX_TIME - tm->tm_year -= 1900; - tm->tm_mon -= 1; - tm->tm_isdst = -1; - mktime(tm); - tm->tm_year += 1900; - tm->tm_mon += 1; - -#if defined(HAVE_TM_ZONE) - *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is - * Sun/DEC-ism */ -#elif defined(HAVE_INT_TIMEZONE) -#ifdef __CYGWIN__ - *tzp = ((tm->tm_isdst > 0) ? (_timezone - 3600) : _timezone); -#else - *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone); -#endif -#else -#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined -#endif - -#else /* !USE_POSIX_TIME */ - *tzp = CTimeZone; -#endif - } - else - { - tm->tm_isdst = 0; - *tzp = 0; - } - } - } - - return 0; -} /* DecodeDateTime() */ - - -/* DecodeTimeOnly() - * Interpret parsed string as time fields only. - */ -int -DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec) -{ - int fmask, - tmask, - type; - int i; - int flen, - val; - int is2digits = FALSE; - int mer = HR24; - - *dtype = DTK_TIME; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - tm->tm_isdst = -1; /* don't know daylight savings time status - * apriori */ - *fsec = 0; - - fmask = DTK_DATE_M; - - for (i = 0; i < nf; i++) - { - switch (ftype[i]) - { - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - break; - - case DTK_NUMBER: - flen = strlen(field[i]); - - if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = DTK_M(type); - switch (type) - { - case RESERV: - switch (val) - { - case DTK_NOW: - tmask = DTK_TIME_M; - *dtype = DTK_TIME; - GetCurrentTime(tm); - break; - - case DTK_ZULU: - tmask = (DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_TIME; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - tm->tm_isdst = 0; - break; - - default: - return -1; - } - - break; - - case IGNORE: - break; - - case AMPM: - mer = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - if ((mer != HR24) && (tm->tm_hour > 12)) - return -1; - if ((mer == AM) && (tm->tm_hour == 12)) - tm->tm_hour = 0; - else if ((mer == PM) && (tm->tm_hour != 12)) - tm->tm_hour += 12; - - if (((tm->tm_hour < 0) || (tm->tm_hour > 23)) - || ((tm->tm_min < 0) || (tm->tm_min > 59)) - || ((tm->tm_sec < 0) || ((tm->tm_sec + *fsec) >= 60))) - return -1; - - if ((fmask & DTK_TIME_M) != DTK_TIME_M) - return -1; - - return 0; -} /* DecodeTimeOnly() */ - - -/* DecodeDate() - * Decode date string which includes delimiters. - * Insist on a complete set of fields. - */ -static int -DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) -{ - double fsec; - - int nf = 0; - int i, - len; - int bc = FALSE; - int is2digits = FALSE; - int type, - val, - dmask = 0; - char *field[MAXDATEFIELDS]; - - /* parse this string... */ - while ((*str != '\0') && (nf < MAXDATEFIELDS)) - { - /* skip field separators */ - while (!isalnum(*str)) - str++; - - field[nf] = str; - if (isdigit(*str)) - { - while (isdigit(*str)) - str++; - } - else if (isalpha(*str)) - { - while (isalpha(*str)) - str++; - } - - if (*str != '\0') - *str++ = '\0'; - nf++; - } - -#if 0 - /* don't allow too many fields */ - if (nf > 3) - return -1; -#endif - - *tmask = 0; - - /* look first for text fields, since that will be unambiguous month */ - for (i = 0; i < nf; i++) - { - if (isalpha(*field[i])) - { - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - dmask = DTK_M(type); - switch (type) - { - case MONTH: - tm->tm_mon = val; - break; - - case ADBC: - bc = (val == BC); - break; - - default: - return -1; - } - if (fmask & dmask) - return -1; - - fmask |= dmask; - *tmask |= dmask; - - /* mark this field as being completed */ - field[i] = NULL; - } - } - - /* now pick up remaining numeric fields */ - for (i = 0; i < nf; i++) - { - if (field[i] == NULL) - continue; - - if ((len = strlen(field[i])) <= 0) - return -1; - - if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits) != 0) - return -1; - - if (fmask & dmask) - return -1; - - fmask |= dmask; - *tmask |= dmask; - } - - if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) - return -1; - - /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ - if (bc) - { - if (tm->tm_year > 0) - tm->tm_year = -(tm->tm_year - 1); - else - elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year); - } - else if (is2digits) - { - if (tm->tm_year < 70) - tm->tm_year += 2000; - else if (tm->tm_year < 100) - tm->tm_year += 1900; - } - - return 0; -} /* DecodeDate() */ - - -/* DecodeTime() - * Decode time string which includes delimiters. - * Only check the lower limit on hours, since this same code - * can be used to represent time spans. - */ -static int -DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec) -{ - char *cp; - - *tmask = DTK_TIME_M; - - tm->tm_hour = strtol(str, &cp, 10); - if (*cp != ':') - return -1; - str = cp + 1; - tm->tm_min = strtol(str, &cp, 10); - if (*cp == '\0') - { - tm->tm_sec = 0; - *fsec = 0; - - } - else if (*cp != ':') - { - return -1; - - } - else - { - str = cp + 1; - tm->tm_sec = strtol(str, &cp, 10); - if (*cp == '\0') - *fsec = 0; - else if (*cp == '.') - { - str = cp; - *fsec = strtod(str, &cp); - if (cp == str) - return -1; - } - else - return -1; - } - - /* do a sanity check */ - if ((tm->tm_hour < 0) - || (tm->tm_min < 0) || (tm->tm_min > 59) - || (tm->tm_sec < 0) || (tm->tm_sec > 59)) - return -1; - - return 0; -} /* DecodeTime() */ - - -/* DecodeNumber() - * Interpret numeric field as a date value in context. - */ -static int -DecodeNumber(int flen, char *str, int fmask, - int *tmask, struct tm * tm, double *fsec, int *is2digits) -{ - int val; - char *cp; - - *tmask = 0; - - val = strtol(str, &cp, 10); - if (cp == str) - return -1; - if (*cp == '.') - { - *fsec = strtod(cp, &cp); - if (*cp != '\0') - return -1; - } - - /* Special case day of year? */ - if ((flen == 3) && (fmask & DTK_M(YEAR)) - && ((val >= 1) && (val <= 366))) - { - *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY)); - tm->tm_yday = val; - j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - - } - - /* - * Enough digits to be unequivocal year? Used to test for 4 digits or - * more, but we now test first for a three-digit doy so anything - * bigger than two digits had better be an explicit year. - thomas - * 1999-01-09 - */ - else if (flen > 2) - { - *tmask = DTK_M(YEAR); - - /* already have a year? then see if we can substitute... */ - if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY))) - && ((tm->tm_year >= 1) && (tm->tm_year <= 31))) - { - tm->tm_mday = tm->tm_year; - *tmask = DTK_M(DAY); - } - - tm->tm_year = val; - } - /* already have year? then could be month */ - else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH))) - && ((val >= 1) && (val <= 12))) - { - *tmask = DTK_M(MONTH); - tm->tm_mon = val; - /* no year and EuroDates enabled? then could be day */ - } - else if ((EuroDates || (fmask & DTK_M(MONTH))) - && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY))) - && ((val >= 1) && (val <= 31))) - { - *tmask = DTK_M(DAY); - tm->tm_mday = val; - } - else if ((!(fmask & DTK_M(MONTH))) - && ((val >= 1) && (val <= 12))) - { - *tmask = DTK_M(MONTH); - tm->tm_mon = val; - } - else if ((!(fmask & DTK_M(DAY))) - && ((val >= 1) && (val <= 31))) - { - *tmask = DTK_M(DAY); - tm->tm_mday = val; - } - else if (!(fmask & DTK_M(YEAR))) - { - *tmask = DTK_M(YEAR); - tm->tm_year = val; - - /* adjust ONLY if exactly two digits... */ - *is2digits = (flen == 2); - } - else - return -1; - - return 0; -} /* DecodeNumber() */ - - -/* DecodeNumberField() - * Interpret numeric string as a concatenated date field. - */ -static int -DecodeNumberField(int len, char *str, int fmask, - int *tmask, struct tm * tm, double *fsec, int *is2digits) -{ - char *cp; - - /* yyyymmdd? */ - if (len == 8) - { - *tmask = DTK_DATE_M; - - tm->tm_mday = atoi(str + 6); - *(str + 6) = '\0'; - tm->tm_mon = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_year = atoi(str + 0); - /* yymmdd or hhmmss? */ - } - else if (len == 6) - { - if (fmask & DTK_DATE_M) - { - *tmask = DTK_TIME_M; - tm->tm_sec = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_min = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_hour = atoi(str + 0); - } - else - { - *tmask = DTK_DATE_M; - tm->tm_mday = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_mon = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_year = atoi(str + 0); - *is2digits = TRUE; - } - - } - else if ((len == 5) && !(fmask & DTK_DATE_M)) - { - *tmask = DTK_DATE_M; - tm->tm_mday = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_mon = 1; - tm->tm_year = atoi(str + 0); - *is2digits = TRUE; - } - else if (strchr(str, '.') != NULL) - { - *tmask = DTK_TIME_M; - tm->tm_sec = strtod((str + 4), &cp); - if (cp == (str + 4)) - return -1; - if (*cp == '.') - *fsec = strtod(cp, NULL); - *(str + 4) = '\0'; - tm->tm_min = strtod((str + 2), &cp); - *(str + 2) = '\0'; - tm->tm_hour = strtod((str + 0), &cp); - - } - else - return -1; - - return 0; -} /* DecodeNumberField() */ - - -/* DecodeTimezone() - * Interpret string as a numeric timezone. - */ -static int -DecodeTimezone(char *str, int *tzp) -{ - int tz; - int hr, - min; - char *cp; - int len; - - /* assume leading character is "+" or "-" */ - hr = strtol((str + 1), &cp, 10); - - /* explicit delimiter? */ - if (*cp == ':') - { - min = strtol((cp + 1), &cp, 10); - - /* otherwise, might have run things together... */ - } - else if ((*cp == '\0') && ((len = strlen(str)) > 3)) - { - min = strtol((str + len - 2), &cp, 10); - *(str + len - 2) = '\0'; - hr = strtol((str + 1), &cp, 10); - - } - else - min = 0; - - tz = (hr * 60 + min) * 60; - if (*str == '-') - tz = -tz; - - *tzp = -tz; - return *cp != '\0'; -} /* DecodeTimezone() */ - - -/* DecodeSpecial() - * Decode text string using lookup table. - * Implement a cache lookup since it is likely that dates - * will be related in format. - */ -static int -DecodeSpecial(int field, char *lowtoken, int *val) -{ - int type; - datetkn *tp; - -#if USE_DATE_CACHE - if ((datecache[field] != NULL) - && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)) - tp = datecache[field]; - else - { -#endif - tp = datebsearch(lowtoken, datetktbl, szdatetktbl); -#if USE_DATE_CACHE - } - datecache[field] = tp; -#endif - if (tp == NULL) - { - type = IGNORE; - *val = 0; - } - else - { - type = tp->type; - switch (type) - { - case TZ: - case DTZ: - case DTZMOD: - *val = FROMVAL(tp); - break; - - default: - *val = tp->value; - break; - } - } - - return type; -} /* DecodeSpecial() */ - - -/* DecodeDateDelta() - * Interpret previously parsed fields for general time interval. - * Return 0 if decoded and -1 if problems. - * - * Allow "date" field DTK_DATE since this could be just - * an unsigned floating point number. - thomas 1997-11-16 - * - * Allow ISO-style time span, with implicit units on number of days - * preceeding an hh:mm:ss field. - thomas 1998-04-30 - */ -int -DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec) -{ - int is_before = FALSE; - - char *cp; - int fmask = 0, - tmask, - type; - int i; - int flen, - val; - double fval; - double sec; - - *dtype = DTK_DELTA; - - type = DTK_SECOND; - tm->tm_year = 0; - tm->tm_mon = 0; - tm->tm_mday = 0; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - *fsec = 0; - - /* read through list backwards to pick up units before values */ - for (i = nf - 1; i >= 0; i--) - { - switch (ftype[i]) - { - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - type = DTK_DAY; - break; - - case DTK_TZ: - - /* - * Timezone is a token with a leading sign character and - * otherwise the same as a non-signed numeric field - */ - case DTK_DATE: - case DTK_NUMBER: - val = strtol(field[i], &cp, 10); - if (*cp == '.') - { - fval = strtod(cp, &cp); - if (*cp != '\0') - return -1; - - if (val < 0) - fval = -(fval); - } - else if (*cp == '\0') - fval = 0; - else - return -1; - - flen = strlen(field[i]); - tmask = 0; /* DTK_M(type); */ - - switch (type) - { - case DTK_MICROSEC: - *fsec += ((val + fval) * 1e-6); - break; - - case DTK_MILLISEC: - *fsec += ((val + fval) * 1e-3); - break; - - case DTK_SECOND: - tm->tm_sec += val; - *fsec += fval; - tmask = DTK_M(SECOND); - break; - - case DTK_MINUTE: - tm->tm_min += val; - if (fval != 0) - tm->tm_sec += (fval * 60); - tmask = DTK_M(MINUTE); - break; - - case DTK_HOUR: - tm->tm_hour += val; - if (fval != 0) - tm->tm_sec += (fval * 3600); - tmask = DTK_M(HOUR); - break; - - case DTK_DAY: - tm->tm_mday += val; - if (fval != 0) - tm->tm_sec += (fval * 86400); - tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); - break; - - case DTK_WEEK: - tm->tm_mday += val * 7; - if (fval != 0) - tm->tm_sec += (fval * (7 * 86400)); - tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); - break; - - case DTK_MONTH: - tm->tm_mon += val; - if (fval != 0) - tm->tm_sec += (fval * (30 * 86400)); - tmask = DTK_M(MONTH); - break; - - case DTK_YEAR: - tm->tm_year += val; - if (fval != 0) - tm->tm_mon += (fval * 12); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_DECADE: - tm->tm_year += val * 10; - if (fval != 0) - tm->tm_mon += (fval * 120); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_CENTURY: - tm->tm_year += val * 100; - if (fval != 0) - tm->tm_mon += (fval * 1200); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_MILLENIUM: - tm->tm_year += val * 1000; - if (fval != 0) - tm->tm_mon += (fval * 12000); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - default: - return -1; - } - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeUnits(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = 0; /* DTK_M(type); */ - switch (type) - { - case UNITS: - type = val; - break; - - case AGO: - is_before = TRUE; - type = val; - break; - - case RESERV: - tmask = (DTK_DATE_M || DTK_TIME_M); - *dtype = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - if (*fsec != 0) - { - TMODULO(*fsec, sec, 1e0); - tm->tm_sec += sec; - } - - if (is_before) - { - *fsec = -(*fsec); - tm->tm_sec = -(tm->tm_sec); - tm->tm_min = -(tm->tm_min); - tm->tm_hour = -(tm->tm_hour); - tm->tm_mday = -(tm->tm_mday); - tm->tm_mon = -(tm->tm_mon); - tm->tm_year = -(tm->tm_year); - } - - /* ensure that at least one time field has been found */ - return (fmask != 0) ? 0 : -1; -} /* DecodeDateDelta() */ - - -/* DecodeUnits() - * Decode text string using lookup table. - * This routine supports time interval decoding. - */ -static int -DecodeUnits(int field, char *lowtoken, int *val) -{ - int type; - datetkn *tp; - -#if USE_DATE_CACHE - if ((deltacache[field] != NULL) - && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)) - tp = deltacache[field]; - else - { -#endif - tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); -#if USE_DATE_CACHE - } - deltacache[field] = tp; -#endif - if (tp == NULL) - { - type = IGNORE; - *val = 0; - } - else - { - type = tp->type; - if ((type == TZ) || (type == DTZ)) - *val = FROMVAL(tp); - else - *val = tp->value; - } - - return type; -} /* DecodeUnits() */ - - -/* datebsearch() - * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this - * is WAY faster than the generic bsearch(). - */ -static datetkn * -datebsearch(char *key, datetkn *base, unsigned int nel) -{ - datetkn *last = base + nel - 1, - *position; - int result; - - while (last >= base) - { - position = base + ((last - base) >> 1); - result = key[0] - position->token[0]; - if (result == 0) - { - result = strncmp(key, position->token, TOKMAXLEN); - if (result == 0) - return position; - } - if (result < 0) - last = position - 1; - else - base = position + 1; - } - return NULL; -} - - -/* EncodeSpecialDateTime() - * Convert reserved datetime data type to string. - */ -static int -EncodeSpecialDateTime(DateTime dt, char *str) -{ - if (DATETIME_IS_RESERVED(dt)) - { - if (DATETIME_IS_INVALID(dt)) - strcpy(str, INVALID); - else if (DATETIME_IS_NOBEGIN(dt)) - strcpy(str, EARLY); - else if (DATETIME_IS_NOEND(dt)) - strcpy(str, LATE); - else if (DATETIME_IS_CURRENT(dt)) - strcpy(str, DCURRENT); - else if (DATETIME_IS_EPOCH(dt)) - strcpy(str, EPOCH); - else - strcpy(str, INVALID); - return TRUE; - } - - return FALSE; -} /* EncodeSpecialDateTime() */ - - -/* EncodeDateOnly() - * Encode date as local time. - */ -int -EncodeDateOnly(struct tm * tm, int style, char *str) -{ - if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) - return -1; - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - if (tm->tm_year > 0) - sprintf(str, "%04d-%02d-%02d", - tm->tm_year, tm->tm_mon, tm->tm_mday); - else - sprintf(str, "%04d-%02d-%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); - break; - - /* compatible with Oracle/Ingres date formats */ - case USE_SQL_DATES: - if (EuroDates) - sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); - if (tm->tm_year > 0) - sprintf((str + 5), "/%04d", tm->tm_year); - else - sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC"); - break; - - /* German-style date format */ - case USE_GERMAN_DATES: - sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); - if (tm->tm_year > 0) - sprintf((str + 5), ".%04d", tm->tm_year); - else - sprintf((str + 5), ".%04d %s", -(tm->tm_year - 1), "BC"); - break; - - /* traditional date-only style for Postgres */ - case USE_POSTGRES_DATES: - default: - if (EuroDates) - sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday); - if (tm->tm_year > 0) - sprintf((str + 5), "-%04d", tm->tm_year); - else - sprintf((str + 5), "-%04d %s", -(tm->tm_year - 1), "BC"); - break; - } - - return TRUE; -} /* EncodeDateOnly() */ - - -/* EncodeTimeOnly() - * Encode time fields only. - */ -int -EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str) -{ - double sec; - - if ((tm->tm_hour < 0) || (tm->tm_hour > 24)) - return -1; - - sec = (tm->tm_sec + fsec); - - sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min); - sprintf((str + 6), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec); - - return TRUE; -} /* EncodeTimeOnly() */ - - -/* EncodeDateTime() - * Encode date and time interpreted as local time. - * Support several date styles: - * Postgres - day mon hh:mm:ss yyyy tz - * SQL - mm/dd/yyyy hh:mm:ss.ss tz - * ISO - yyyy-mm-dd hh:mm:ss+/-tz - * German - dd.mm/yyyy hh:mm:ss tz - * Variants (affects order of month and day for Postgres and SQL styles): - * US - mm/dd/yyyy - * European - dd/mm/yyyy - */ -int -EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str) -{ - int day, - hour, - min; - double sec; - - if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) - return -1; - - sec = (tm->tm_sec + fsec); - - switch (style) - { - /* compatible with ISO date formats */ - - case USE_ISO_DATES: - if (tm->tm_year > 0) - { - sprintf(str, "%04d-%02d-%02d %02d:%02d:", - tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); - sprintf((str + 17), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - if (tzp != NULL) - { - hour = -(*tzp / 3600); - min = ((abs(*tzp) / 60) % 60); - } - else - { - hour = 0; - min = 0; - } - sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min); - } - - } - else - { - if (tm->tm_hour || tm->tm_min) - sprintf(str, "%04d-%02d-%02d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC"); - else - sprintf(str, "%04d-%02d-%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); - } - break; - - /* compatible with Oracle/Ingres date formats */ - case USE_SQL_DATES: - if (EuroDates) - sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); - - if (tm->tm_year > 0) - { - sprintf((str + 5), "/%04d %02d:%02d:%05.2f", - tm->tm_year, tm->tm_hour, tm->tm_min, sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 22), " "); - strcpy((str + 23), *tzn); - } - - } - else - sprintf((str + 5), "/%04d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC"); - break; - - /* German variant on European style */ - case USE_GERMAN_DATES: - sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); - if (tm->tm_year > 0) - { - sprintf((str + 5), ".%04d %02d:%02d:%05.2f", - tm->tm_year, tm->tm_hour, tm->tm_min, sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 22), " "); - strcpy((str + 23), *tzn); - } - - } - else - sprintf((str + 5), ".%04d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC"); - break; - - /* backward-compatible with traditional Postgres abstime dates */ - case USE_POSTGRES_DATES: - default: - day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); - tm->tm_wday = j2day(day); - - strncpy(str, days[tm->tm_wday], 3); - strcpy((str + 3), " "); - - if (EuroDates) - sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]); - else - sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday); - - if (tm->tm_year > 0) - { - sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min); - if (fsec != 0) - { - sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year); - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 27), " "); - strncpy((str + 28), *tzn, MAXTZLEN); - } - } - else - { - sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year); - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 24), " "); - strncpy((str + 25), *tzn, MAXTZLEN); - } - } - - } - else - { - sprintf((str + 10), " %02d:%02d %04d %s", - tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC"); - } - break; - } - - return TRUE; -} /* EncodeDateTime() */ - - -/* EncodeTimeSpan() - * Interpret time structure as a delta time and convert to string. - * - * Support "traditional Postgres" and ISO-8601 styles. - * Actually, afaik ISO does not address time interval formatting, - * but this looks similar to the spec for absolute date/time. - * - thomas 1998-04-30 - */ -int -EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str) -{ - int is_before = FALSE; - int is_nonzero = FALSE; - char *cp = str; - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - break; - - default: - strcpy(cp, "@ "); - cp += strlen(cp); - break; - } - - if (tm->tm_year != 0) - { - is_before |= (tm->tm_year < 0); - sprintf(cp, "%d year%s", - abs(tm->tm_year), ((abs(tm->tm_year) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - if (tm->tm_mon != 0) - { - is_before |= (tm->tm_mon < 0); - sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""), - abs(tm->tm_mon), ((abs(tm->tm_mon) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - if (tm->tm_mday != 0) - { - is_before |= (tm->tm_mday < 0); - sprintf(cp, "%s%d", (is_nonzero ? " " : ""), abs(tm->tm_mday)); - cp += strlen(cp); - is_nonzero = TRUE; - } - is_before |= ((tm->tm_hour < 0) || (tm->tm_min < 0)); - sprintf(cp, "%s%02d:%02d", (is_nonzero ? " " : ""), - abs(tm->tm_hour), abs(tm->tm_min)); - cp += strlen(cp); - if ((tm->tm_hour != 0) || (tm->tm_min != 0)) - is_nonzero = TRUE; - - /* fractional seconds? */ - if (fsec != 0) - { - fsec += tm->tm_sec; - is_before |= (fsec < 0); - sprintf(cp, ":%05.2f", fabs(fsec)); - cp += strlen(cp); - is_nonzero = TRUE; - - /* otherwise, integer seconds only? */ - } - else if (tm->tm_sec != 0) - { - is_before |= (tm->tm_sec < 0); - sprintf(cp, ":%02d", abs(tm->tm_sec)); - cp += strlen(cp); - is_nonzero = TRUE; - } - break; - - case USE_POSTGRES_DATES: - default: - if (tm->tm_mday != 0) - { - is_before |= (tm->tm_mday < 0); - sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""), - abs(tm->tm_mday), ((abs(tm->tm_mday) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - if (tm->tm_hour != 0) - { - is_before |= (tm->tm_hour < 0); - sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""), - abs(tm->tm_hour), ((abs(tm->tm_hour) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - if (tm->tm_min != 0) - { - is_before |= (tm->tm_min < 0); - sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""), - abs(tm->tm_min), ((abs(tm->tm_min) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - /* fractional seconds? */ - if (fsec != 0) - { - fsec += tm->tm_sec; - is_before |= (fsec < 0); - sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), fabs(fsec)); - cp += strlen(cp); - is_nonzero = TRUE; - - /* otherwise, integer seconds only? */ - } - else if (tm->tm_sec != 0) - { - is_before |= (tm->tm_sec < 0); - sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""), - abs(tm->tm_sec), ((abs(tm->tm_sec) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - break; - } - - /* identically zero? then put in a unitless zero... */ - if (!is_nonzero) - { - strcat(cp, "0"); - cp += strlen(cp); - } - - if (is_before) - { - strcat(cp, " ago"); - cp += strlen(cp); - } - - return 0; -} /* EncodeTimeSpan() */ - - -#if defined(linux) && defined(__powerpc__) -int -datetime_is_epoch(double j) -{ - static union - { - double epoch; - unsigned char c[8]; - } u; - - u.c[0] = 0x80; /* sign bit */ - u.c[1] = 0x10; /* DBL_MIN */ - - return j == u.epoch; -} -int -datetime_is_current(double j) -{ - static union - { - double current; - unsigned char c[8]; - } u; - - u.c[1] = 0x10; /* DBL_MIN */ - - return j == u.current; -} - -#endif diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index e8f6d2cd47..7281d4f4dc 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,45 +1,45 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.3 2000/02/08 15:56:55 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.4 2000/02/16 17:24:48 thomas Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc * * - * TO_CHAR(); TO_DATETIME(); TO_DATE(); TO_NUMBER(); + * TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER(); * - * The PostgreSQL routines for a DateTime/int/float/numeric formatting, + * The PostgreSQL routines for a timestamp/int/float/numeric formatting, * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * * * Cache & Memory: * Routines use (itself) internal cache for format pictures. If - * new format arg is same as a last format string, routines not + * new format arg is same as a last format string, routines do not * call the format-parser. * - * The cache use static buffer and is persistent across transactions. If - * format-picture is bigger than cache buffer, parser is called always. + * The cache uses a static buffer and is persistent across transactions. + * If format-picture is bigger than cache buffer, parser is called always. * * NOTE for Number version: * All in this version is implemented as keywords ( => not used * suffixes), because a format picture is for *one* item (number) - * only. It not is as a datetime version, where each keyword (can) + * only. It not is as a timestamp version, where each keyword (can) * has suffix. * - * NOTE for DateTime version: - * In this modul is *not* used POSIX 'struct tm' type, but + * NOTE for Timestamp routines: + * In this module the POSIX 'struct tm' type is *not* used, but rather * PgSQL type, which has tm_mon based on one (*non* zero) and * year *not* based on 1900, but is used full year number. - * Modul support AC / BC years. + * Module supports AC / BC years. * * Supported types for to_char(): * - * Timestamp, DateTime, Numeric, int4, int8, float4, float8 + * Timestamp, Numeric, int4, int8, float4, float8 * * Supported types for reverse conversion: * - * Datetime - to_datetime() + * Timestamp - to_timestamp() * Date - to_date() * Numeric - to_number() * @@ -108,7 +108,7 @@ #define MAXDOUBLEWIDTH 128 /* ---------- - * External (defined in PgSQL dt.c (datetime utils)) + * External (defined in PgSQL dt.c (timestamp utils)) * ---------- */ extern char *months[], /* month abbreviation */ @@ -1377,14 +1377,14 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): SSSS is not supported"); + elog(ERROR, "to_datatime(): SSSS is not supported"); } return -1; } #define CHECK_SEQ_SEARCH(_l, _s) { \ if (_l <= 0) { \ - elog(ERROR, "to_datatime()/to_timestamp(): bad value for %s", _s); \ + elog(ERROR, "to_datatime(): bad value for %s", _s); \ } \ } @@ -1600,7 +1600,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): WW is not supported"); + elog(ERROR, "to_datatime(): WW is not supported"); case DCH_Q: if (flag == TO_CHAR) { sprintf(inout, "%d", (tm->tm_mon-1)/3+1); @@ -1611,7 +1611,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 0; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): Q is not supported"); + elog(ERROR, "to_datatime(): Q is not supported"); case DCH_CC: if (flag == TO_CHAR) { @@ -1625,7 +1625,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): CC is not supported"); + elog(ERROR, "to_datatime(): CC is not supported"); case DCH_Y_YYY: if (flag == TO_CHAR) { i= YEAR_ABS(tm->tm_year) / 1000; @@ -1764,7 +1764,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 0; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): W is not supported"); + elog(ERROR, "to_datatime(): W is not supported"); case DCH_J: if (flag == TO_CHAR) { @@ -1773,7 +1773,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): J is not supported"); + elog(ERROR, "to_datatime(): J is not supported"); } return -1; } @@ -1783,11 +1783,11 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ***************************************************************************/ /* ------------------- - * DATETIME to_char() + * TIMESTAMP to_char() * ------------------- */ text * -datetime_to_char(DateTime *dt, text *fmt) +timestamp_to_char(Timestamp *dt, text *fmt) { static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; static char CacheStr[ DCH_CACHE_SIZE +1]; @@ -1814,14 +1814,14 @@ datetime_to_char(DateTime *dt, text *fmt) tm->tm_mday =1; tm->tm_isdst =0; tm->tm_mon =1; - if (DATETIME_IS_EPOCH(*dt)) + if (TIMESTAMP_IS_EPOCH(*dt)) { - datetime2tm(SetDateTime(*dt), NULL, tm, &fsec, NULL); - } else if (DATETIME_IS_CURRENT(*dt)) { - datetime2tm(SetDateTime(*dt), &tz, tm, &fsec, &tzn); + timestamp2tm(SetTimestamp(*dt), NULL, tm, &fsec, NULL); + } else if (TIMESTAMP_IS_CURRENT(*dt)) { + timestamp2tm(SetTimestamp(*dt), &tz, tm, &fsec, &tzn); } else { - if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "to_char(): Unable to convert datetime to tm"); + if (timestamp2tm(*dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "to_char(): Unable to convert timestamp to tm"); } tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7; @@ -1902,32 +1902,22 @@ datetime_to_char(DateTime *dt, text *fmt) } -/* ------------------- - * TIMESTAMP to_char() - * ------------------- - */ -text * -timestamp_to_char(time_t dt, text *fmt) -{ - return datetime_to_char( timestamp_datetime(dt), fmt); -} - /* --------------------- - * TO_DATETIME() + * TO_TIMESTAMP() * - * Make DateTime from date_str which is formated at argument 'fmt' - * ( to_datetime is reverse to_char() ) + * Make Timestamp from date_str which is formated at argument 'fmt' + * ( to_timestamp is reverse to_char() ) * --------------------- */ -DateTime * -to_datetime(text *date_str, text *fmt) +Timestamp * +to_timestamp(text *date_str, text *fmt) { static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; static char CacheStr[ DCH_CACHE_SIZE +1]; FormatNode *format; int flag=0; - DateTime *result; + Timestamp *result; char *str; int len=0, fsec=0, @@ -1942,7 +1932,7 @@ to_datetime(text *date_str, text *fmt) tm->tm_mday =1; tm->tm_isdst =0; tm->tm_mon =1; - result = palloc(sizeof(DateTime)); + result = palloc(sizeof(Timestamp)); len = VARSIZE(fmt) - VARHDRSZ; @@ -2060,8 +2050,8 @@ to_datetime(text *date_str, text *fmt) #ifdef DEBUG_TO_FROM_CHAR NOTICE_TM; #endif - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "to_datatime()/to_timestamp(): can't convert 'tm' to datetime."); + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "to_datatime(): can't convert 'tm' to timestamp."); return result; } @@ -2074,18 +2064,7 @@ to_datetime(text *date_str, text *fmt) DateADT to_date(text *date_str, text *fmt) { - return datetime_date( to_datetime(date_str, fmt) ); -} - -/* ---------- - * TO_TIMESTAMP - * Make timestamp from date_str which is formated at argument 'fmt' - * ---------- - */ -time_t -to_timestamp(text *date_str, text *fmt) -{ - return datetime_timestamp( to_datetime(date_str, fmt) ); + return timestamp_date( to_timestamp(date_str, fmt) ); } /********************************************************************** diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 71a636feeb..28a94f5e16 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -1,23 +1,41 @@ /* * nabstime.c - * parse almost any absolute date getdate(3) can (& some it can't) + * Utilities for the built-in type "AbsoluteTime". + * Functions for the built-in type "RelativeTime". + * Functions for the built-in type "TimeInterval". * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nabstime.c,v 1.65 2000/01/26 05:57:14 momjian Exp $ * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.66 2000/02/16 17:24:48 thomas Exp $ + * + * NOTES + * + *------------------------------------------------------------------------- */ #include +#include +#include #include #include "postgres.h" #ifdef HAVE_FLOAT_H #include #endif + #ifdef HAVE_LIMITS_H #include +#ifndef MAXINT +#define MAXINT INT_MAX #endif +#else +#ifdef HAVE_VALUES_H +#include +#endif +#endif + #ifndef USE_POSIX_TIME #include #endif @@ -26,11 +44,80 @@ #include "miscadmin.h" #include "utils/builtins.h" + +#if 0 static AbsoluteTime tm2abstime(struct tm * tm, int tz); +#endif + #define MIN_DAYNUM -24856 /* December 13, 1901 */ #define MAX_DAYNUM 24854 /* January 18, 2038 */ +#define INVALID_RELTIME_STR "Undefined RelTime" +#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1) +#define RELTIME_LABEL '@' +#define RELTIME_PAST "ago" +#define DIRMAXLEN (sizeof(RELTIME_PAST)-1) + +/* + * Unix epoch is Jan 1 00:00:00 1970. + * Postgres knows about times sixty-eight years on either side of that + * for these 4-byte types. + * + * "tinterval" is two 4-byte fields. + * Definitions for parsing tinterval. + */ + +#define IsSpace(C) ((C) == ' ') + +#define T_INTERVAL_INVAL 0 /* data represents no valid interval */ +#define T_INTERVAL_VALID 1 /* data represents a valid interval */ +/* + * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST'] + * 0 1 2 3 4 5 6 + * 1234567890123456789012345678901234567890123456789012345678901234 + * + * we allocate some extra -- timezones are usually 3 characters but + * this is not in the POSIX standard... + */ +#define T_INTERVAL_LEN 80 +#define INVALID_INTERVAL_STR "Undefined Range" +#define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1) + +#define ABSTIMEMIN(t1, t2) abstimele((t1),(t2)) ? (t1) : (t2) +#define ABSTIMEMAX(t1, t2) abstimelt((t1),(t2)) ? (t2) : (t1) + +#ifdef NOT_USED +static char *unit_tab[] = { + "second", "seconds", "minute", "minutes", + "hour", "hours", "day", "days", "week", "weeks", +"month", "months", "year", "years"}; + +#define UNITMAXLEN 7 /* max length of a unit name */ +#define NUNITS 14 /* number of different units */ + +/* table of seconds per unit (month = 30 days, year = 365 days) */ +static int sec_tab[] = { + 1, 1, 60, 60, + 3600, 3600, 86400, 86400, 604800, 604800, +2592000, 2592000, 31536000, 31536000}; +#endif + +/* + * Function prototypes -- internal to this file only + */ + +static void reltime2tm(RelativeTime time, struct tm * tm); + +#ifdef NOT_USED +static int correct_unit(char *unit, int *unptr); +static int correct_dir(char *direction, int *signptr); + +#endif + +static int istinterval(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end); /* GetCurrentAbsoluteTime() * Get the current system time. Set timezone parameters if not specified elsewhere. @@ -491,10 +578,10 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2) /* datetime_abstime() - * Convert datetime to abstime. + * Convert timestamp to abstime. */ AbsoluteTime -datetime_abstime(DateTime *datetime) +timestamp_abstime(Timestamp *timestamp) { AbsoluteTime result; @@ -502,35 +589,35 @@ datetime_abstime(DateTime *datetime) struct tm tt, *tm = &tt; - if (!PointerIsValid(datetime)) + if (!PointerIsValid(timestamp)) { result = INVALID_ABSTIME; } - else if (DATETIME_IS_INVALID(*datetime)) + else if (TIMESTAMP_IS_INVALID(*timestamp)) { result = INVALID_ABSTIME; } - else if (DATETIME_IS_NOBEGIN(*datetime)) + else if (TIMESTAMP_IS_NOBEGIN(*timestamp)) { result = NOSTART_ABSTIME; } - else if (DATETIME_IS_NOEND(*datetime)) + else if (TIMESTAMP_IS_NOEND(*timestamp)) { result = NOEND_ABSTIME; } else { - if (DATETIME_IS_RELATIVE(*datetime)) + if (TIMESTAMP_IS_RELATIVE(*timestamp)) { - datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL); + timestamp2tm(SetTimestamp(*timestamp), NULL, tm, &fsec, NULL); result = tm2abstime(tm, 0); } - else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0) + else if (timestamp2tm(*timestamp, NULL, tm, &fsec, NULL) == 0) { result = tm2abstime(tm, 0); @@ -542,39 +629,39 @@ datetime_abstime(DateTime *datetime) }; return result; -} /* datetime_abstime() */ +} /* timestamp_abstime() */ -/* abstime_datetime() - * Convert abstime to datetime. +/* abstime_timestamp() + * Convert abstime to timestamp. */ -DateTime * -abstime_datetime(AbsoluteTime abstime) +Timestamp * +abstime_timestamp(AbsoluteTime abstime) { - DateTime *result; + Timestamp *result; - if (!PointerIsValid(result = palloc(sizeof(DateTime)))) - elog(ERROR, "Unable to allocate space to convert abstime to datetime"); + if (!PointerIsValid(result = palloc(sizeof(Timestamp)))) + elog(ERROR, "Unable to allocate space to convert abstime to timestamp"); switch (abstime) { case INVALID_ABSTIME: - DATETIME_INVALID(*result); + TIMESTAMP_INVALID(*result); break; case NOSTART_ABSTIME: - DATETIME_NOBEGIN(*result); + TIMESTAMP_NOBEGIN(*result); break; case NOEND_ABSTIME: - DATETIME_NOEND(*result); + TIMESTAMP_NOEND(*result); break; case EPOCH_ABSTIME: - DATETIME_EPOCH(*result); + TIMESTAMP_EPOCH(*result); break; case CURRENT_ABSTIME: - DATETIME_CURRENT(*result); + TIMESTAMP_CURRENT(*result); break; default: @@ -583,4 +670,1195 @@ abstime_datetime(AbsoluteTime abstime) }; return result; -} /* abstime_datetime() */ +} /* abstime_timestamp() */ + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* + * reltimein - converts a reltime string in an internal format + */ +RelativeTime +reltimein(char *str) +{ + RelativeTime result; + + struct tm tt, + *tm = &tt; + double fsec; + int dtype; + char *field[MAXDATEFIELDS]; + int nf, + ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) date external representation"); + + if (strlen(str) > MAXDATELEN) + elog(ERROR, "Bad (length) reltime external representation '%s'", str); + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) + elog(ERROR, "Bad reltime external representation '%s'", str); + + switch (dtype) + { + case DTK_DELTA: + result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec); + result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60)); + return result; + + default: + return INVALID_RELTIME; + } + + elog(ERROR, "Bad reltime (internal coding error) '%s'", str); + return INVALID_RELTIME; +} /* reltimein() */ + + +/* + * reltimeout - converts the internal format to a reltime string + */ +char * +reltimeout(RelativeTime time) +{ + char *result; + struct tm tt, + *tm = &tt; + char buf[MAXDATELEN + 1]; + + if (time == INVALID_RELTIME) + { + strcpy(buf, INVALID_RELTIME_STR); + + } + else + { + reltime2tm(time, tm); + EncodeTimeSpan(tm, 0, DateStyle, buf); + } + + result = palloc(strlen(buf) + 1); + strcpy(result, buf); + + return result; +} /* reltimeout() */ + + +static void +reltime2tm(RelativeTime time, struct tm * tm) +{ + TMODULO(time, tm->tm_year, 31536000); + TMODULO(time, tm->tm_mon, 2592000); + TMODULO(time, tm->tm_mday, 86400); + TMODULO(time, tm->tm_hour, 3600); + TMODULO(time, tm->tm_min, 60); + TMODULO(time, tm->tm_sec, 1); + + return; +} /* reltime2tm() */ + +#ifdef NOT_USED +int +dummyfunc() +{ + char *timestring; + long quantity; + int i; + int unitnr; + + timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR), + UNITMAXLEN) + 1); + if (timevalue == INVALID_RELTIME) + { + strcpy(timestring, INVALID_RELTIME_STR); + return timestring; + } + + if (timevalue == 0) + i = 1; /* unit = 'seconds' */ + else + for (i = 12; i >= 0; i = i - 2) + if ((timevalue % sec_tab[i]) == 0) + break; /* appropriate unit found */ + unitnr = i; + quantity = (timevalue / sec_tab[unitnr]); + if (quantity > 1 || quantity < -1) + unitnr++; /* adjust index for PLURAL of unit */ + if (quantity >= 0) + sprintf(timestring, "%c %lu %s", RELTIME_LABEL, + quantity, unit_tab[unitnr]); + else + sprintf(timestring, "%c %lu %s %s", RELTIME_LABEL, + (quantity * -1), unit_tab[unitnr], RELTIME_PAST); + return timestring; +} + +#endif + + +/* + * tintervalin - converts an interval string to an internal format + */ +TimeInterval +tintervalin(char *intervalstr) +{ + int error; + AbsoluteTime i_start, + i_end, + t1, + t2; + TimeInterval interval; + + interval = (TimeInterval) palloc(sizeof(TimeIntervalData)); + error = istinterval(intervalstr, &t1, &t2); + if (error == 0) + interval->status = T_INTERVAL_INVAL; + if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) + interval->status = T_INTERVAL_INVAL; /* undefined */ + else + { + i_start = ABSTIMEMIN(t1, t2); + i_end = ABSTIMEMAX(t1, t2); + interval->data[0] = i_start; + interval->data[1] = i_end; + interval->status = T_INTERVAL_VALID; + } + return interval; +} + + +/* + * tintervalout - converts an internal interval format to a string + * + */ +char * +tintervalout(TimeInterval interval) +{ + char *i_str, + *p; + + i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */ + strcpy(i_str, "[\""); + if (interval->status == T_INTERVAL_INVAL) + strcat(i_str, INVALID_INTERVAL_STR); + else + { + p = nabstimeout(interval->data[0]); + strcat(i_str, p); + pfree(p); + strcat(i_str, "\" \""); + p = nabstimeout(interval->data[1]); + strcat(i_str, p); + pfree(p); + } + strcat(i_str, "\"]\0"); + return i_str; +} + + +/***************************************************************************** + * PUBLIC ROUTINES * + *****************************************************************************/ + +RelativeTime +interval_reltime(Interval *interval) +{ + RelativeTime time; + int year, + month; + double span; + + if (!PointerIsValid(interval)) + time = INVALID_RELTIME; + + if (INTERVAL_IS_INVALID(*interval)) + { + time = INVALID_RELTIME; + + } + else + { + if (interval->month == 0) + { + year = 0; + month = 0; + + } + else if (abs(interval->month) >= 12) + { + year = (interval->month / 12); + month = (interval->month % 12); + + } + else + { + year = 0; + month = interval->month; + } + + span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time); + + time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME); + } + + return time; +} /* interval_reltime() */ + + +Interval * +reltime_interval(RelativeTime reltime) +{ + Interval *result; + int year, + month; + + if (!PointerIsValid(result = palloc(sizeof(Interval)))) + elog(ERROR, "Memory allocation failed, can't convert reltime to interval"); + + switch (reltime) + { + case INVALID_RELTIME: + INTERVAL_INVALID(*result); + break; + + default: + TMODULO(reltime, year, 31536000); + TMODULO(reltime, month, 2592000); + + result->time = reltime; + result->month = ((12 * year) + month); + } + + return result; +} /* reltime_interval() */ + + +/* + * mktinterval - creates a time interval with endpoints t1 and t2 + */ +TimeInterval +mktinterval(AbsoluteTime t1, AbsoluteTime t2) +{ + AbsoluteTime tstart = ABSTIMEMIN(t1, t2), + tend = ABSTIMEMAX(t1, t2); + TimeInterval interval; + + interval = (TimeInterval) palloc(sizeof(TimeIntervalData)); + if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) + interval->status = T_INTERVAL_INVAL; + else + { + interval->status = T_INTERVAL_VALID; + interval->data[0] = tstart; + interval->data[1] = tend; + } + + return interval; +} + +/* + * timepl, timemi and abstimemi use the formula + * abstime + reltime = abstime + * so abstime - reltime = abstime + * and abstime - abstime = reltime + */ + +/* + * timepl - returns the value of (abstime t1 + relime t2) + */ +AbsoluteTime +timepl(AbsoluteTime t1, RelativeTime t2) +{ + if (t1 == CURRENT_ABSTIME) + t1 = GetCurrentTransactionStartTime(); + + if (AbsoluteTimeIsReal(t1) && + RelativeTimeIsValid(t2) && + ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2) + : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */ + return t1 + t2; + + return INVALID_ABSTIME; +} + + +/* + * timemi - returns the value of (abstime t1 - reltime t2) + */ +AbsoluteTime +timemi(AbsoluteTime t1, RelativeTime t2) +{ + if (t1 == CURRENT_ABSTIME) + t1 = GetCurrentTransactionStartTime(); + + if (AbsoluteTimeIsReal(t1) && + RelativeTimeIsValid(t2) && + ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2) + : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */ + return t1 - t2; + + return INVALID_ABSTIME; +} + + +/* + * abstimemi - returns the value of (abstime t1 - abstime t2) + */ +static RelativeTime +abstimemi(AbsoluteTime t1, AbsoluteTime t2) +{ + if (t1 == CURRENT_ABSTIME) + t1 = GetCurrentTransactionStartTime(); + if (t2 == CURRENT_ABSTIME) + t2 = GetCurrentTransactionStartTime(); + + if (AbsoluteTimeIsReal(t1) && + AbsoluteTimeIsReal(t2)) + return t1 - t2; + + return INVALID_RELTIME; +} + + +/* + * intinterval - returns 1, iff absolute date is in the interval + */ +int +intinterval(AbsoluteTime t, TimeInterval interval) +{ + if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME) + return (abstimege(t, interval->data[0]) && + abstimele(t, interval->data[1])); + return 0; +} + +/* + * tintervalrel - returns relative time corresponding to interval + */ +RelativeTime +tintervalrel(TimeInterval interval) +{ + if (interval->status == T_INTERVAL_VALID) + return abstimemi(interval->data[1], interval->data[0]); + else + return INVALID_RELTIME; +} + +/* + * timenow - returns time "now", internal format + * + * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992 + */ +AbsoluteTime +timenow() +{ + time_t sec; + + if (time(&sec) < 0) + return INVALID_ABSTIME; + return (AbsoluteTime) sec; +} + +/* + * reltimeeq - returns 1, iff arguments are equal + * reltimene - returns 1, iff arguments are not equal + * reltimelt - returns 1, iff t1 less than t2 + * reltimegt - returns 1, iff t1 greater than t2 + * reltimele - returns 1, iff t1 less than or equal to t2 + * reltimege - returns 1, iff t1 greater than or equal to t2 + */ +bool +reltimeeq(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 == t2; +} + +bool +reltimene(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 != t2; +} + +bool +reltimelt(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 < t2; +} + +bool +reltimegt(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 > t2; +} + +bool +reltimele(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 <= t2; +} + +bool +reltimege(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 >= t2; +} + + +/* + * tintervalsame - returns 1, iff interval i1 is same as interval i2 + * Check begin and end time. + */ +bool +tintervalsame(TimeInterval i1, TimeInterval i2) +{ + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + return (abstimeeq(i1->data[0], i2->data[0]) && + abstimeeq(i1->data[1], i2->data[1])); +} /* tintervalsame() */ + + +/* + * tintervaleq - returns 1, iff interval i1 is equal to interval i2 + * Check length of intervals. + */ +bool +tintervaleq(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) == (t21 - t20); +} /* tintervaleq() */ + +/* + * tintervalne - returns 1, iff interval i1 is not equal to interval i2 + * Check length of intervals. + */ +bool +tintervalne(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) != (t21 - t20); +} /* tintervalne() */ + +/* + * tintervallt - returns TRUE, iff interval i1 is less than interval i2 + * Check length of intervals. + */ +bool +tintervallt(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) < (t21 - t20); +} /* tintervallt() */ + +/* + * tintervalle - returns TRUE, iff interval i1 is less than or equal to interval i2 + * Check length of intervals. + */ +bool +tintervalle(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) <= (t21 - t20); +} /* tintervalle() */ + +/* + * tintervalgt - returns TRUE, iff interval i1 is less than interval i2 + * Check length of intervals. + */ +bool +tintervalgt(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) > (t21 - t20); +} /* tintervalgt() */ + +/* + * tintervalge - returns TRUE, iff interval i1 is less than or equal to interval i2 + * Check length of intervals. + */ +bool +tintervalge(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + t10 = i1->data[0]; + t11 = i1->data[1]; + t20 = i2->data[0]; + t21 = i2->data[1]; + + if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) + || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) + return FALSE; + + if (t10 == CURRENT_ABSTIME) + t10 = GetCurrentTransactionStartTime(); + if (t11 == CURRENT_ABSTIME) + t11 = GetCurrentTransactionStartTime(); + if (t20 == CURRENT_ABSTIME) + t20 = GetCurrentTransactionStartTime(); + if (t21 == CURRENT_ABSTIME) + t21 = GetCurrentTransactionStartTime(); + + return (t11 - t10) >= (t21 - t20); +} /* tintervalge() */ + + +/* + * tintervalleneq - returns 1, iff length of interval i is equal to + * reltime t + */ +bool +tintervalleneq(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt == t; +} + +/* + * tintervallenne - returns 1, iff length of interval i is not equal + * to reltime t + */ +bool +tintervallenne(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt != t; +} + +/* + * tintervallenlt - returns 1, iff length of interval i is less than + * reltime t + */ +bool +tintervallenlt(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt < t; +} + +/* + * tintervallengt - returns 1, iff length of interval i is greater than + * reltime t + */ +bool +tintervallengt(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt > t; +} + +/* + * tintervallenle - returns 1, iff length of interval i is less or equal + * than reltime t + */ +bool +tintervallenle(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt <= t; +} + +/* + * tintervallenge - returns 1, iff length of interval i is greater or + * equal than reltime t + */ +bool +tintervallenge(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt >= t; +} + +/* + * tintervalct - returns 1, iff interval i1 contains interval i2 + */ +bool +tintervalct(TimeInterval i1, TimeInterval i2) +{ + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return 0; + return (abstimele(i1->data[0], i2->data[0]) && + abstimege(i1->data[1], i2->data[1])); +} + +/* + * tintervalov - returns 1, iff interval i1 (partially) overlaps i2 + */ +bool +tintervalov(TimeInterval i1, TimeInterval i2) +{ + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return 0; + return (!(abstimelt(i1->data[1], i2->data[0]) || + abstimegt(i1->data[0], i2->data[1]))); +} + +/* + * tintervalstart - returns the start of interval i + */ +AbsoluteTime +tintervalstart(TimeInterval i) +{ + if (i->status == T_INTERVAL_INVAL) + return INVALID_ABSTIME; + return i->data[0]; +} + +/* + * tintervalend - returns the end of interval i + */ +AbsoluteTime +tintervalend(TimeInterval i) +{ + if (i->status == T_INTERVAL_INVAL) + return INVALID_ABSTIME; + return i->data[1]; +} + + +/***************************************************************************** + * PRIVATE ROUTINES * + *****************************************************************************/ + +#ifdef NOT_USED +/* + * isreltime - returns 1, iff datestring is of type reltime + * 2, iff datestring is 'invalid time' identifier + * 0, iff datestring contains a syntax error + * VALID time less or equal +/- `@ 68 years' + * + */ +int +isreltime(char *str) +{ + struct tm tt, + *tm = &tt; + double fsec; + int dtype; + char *field[MAXDATEFIELDS]; + int nf, + ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return 0; + + if (strlen(str) > MAXDATELEN) + return 0; + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) + return 0; + + switch (dtype) + { + case (DTK_DELTA): + return (abs(tm->tm_year) <= 68) ? 1 : 0; + break; + + case (DTK_INVALID): + return 2; + break; + + default: + return 0; + break; + } + + return 0; +} /* isreltime() */ + +#endif + +#ifdef NOT_USED +int +dummyfunc() +{ + char *p; + char c; + int i; + char unit[UNITMAXLEN]; + char direction[DIRMAXLEN]; + int localSign; + int localUnitNumber; + long localQuantity; + + if (!PointerIsValid(sign)) + sign = &localSign; + + if (!PointerIsValid(unitnr)) + unitnr = &localUnitNumber; + + if (!PointerIsValid(quantity)) + quantity = &localQuantity; + + unit[0] = '\0'; + direction[0] = '\0'; + p = timestring; + /* skip leading blanks */ + while ((c = *p) != '\0') + { + if (c != ' ') + break; + p++; + } + + /* Test whether 'invalid time' identifier or not */ + if (!strncmp(INVALID_RELTIME_STR, p, strlen(INVALID_RELTIME_STR) + 1)) + return 2; /* correct 'invalid time' identifier found */ + + /* handle label of relative time */ + if (c != RELTIME_LABEL) + return 0; /* syntax error */ + c = *++p; + if (c != ' ') + return 0; /* syntax error */ + p++; + /* handle the quantity */ + *quantity = 0; + for (;;) + { + c = *p; + if (isdigit(c)) + { + *quantity = *quantity * 10 + (c - '0'); + p++; + } + else + { + if (c == ' ') + break; /* correct quantity found */ + else + return 0; /* syntax error */ + } + } + + /* handle unit */ + p++; + i = 0; + for (;;) + { + c = *p; + if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1)) + { + unit[i] = c; + p++; + i++; + } + else + { + if ((c == ' ' || c == '\0') + && correct_unit(unit, unitnr)) + break; /* correct unit found */ + else + return 0; /* syntax error */ + } + } + + /* handle optional direction */ + if (c == ' ') + p++; + i = 0; + *sign = 1; + for (;;) + { + c = *p; + if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1)) + { + direction[i] = c; + p++; + i++; + } + else + { + if ((c == ' ' || c == '\0') && i == 0) + { + *sign = 1; + break; /* no direction specified */ + } + if ((c == ' ' || c == '\0') && i != 0) + { + direction[i] = '\0'; + correct_dir(direction, sign); + break; /* correct direction found */ + } + else + return 0; /* syntax error */ + } + } + + return 1; +} + +/* + * correct_unit - returns 1, iff unit is a correct unit description + * + * output parameter: + * unptr: points to an integer which is the appropriate unit number + * (see function isreltime()) + */ +static int +correct_unit(char *unit, int *unptr) +{ + int j = 0; + + while (j < NUNITS) + { + if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0) + { + *unptr = j; + return 1; + } + j++; + } + return 0; /* invalid unit descriptor */ +} + +/* + * correct_dir - returns 1, iff direction is a correct identifier + * + * output parameter: + * signptr: points to -1 if dir corresponds to past tense + * else to 1 + */ +static int +correct_dir(char *direction, int *signptr) +{ + *signptr = 1; + if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST) + 1) == 0) + { + *signptr = -1; + return 1; + } + else + return 0; /* invalid direction descriptor */ +} + +#endif + +/* + * istinterval - returns 1, iff i_string is a valid interval descr. + * 0, iff i_string is NOT a valid interval desc. + * 2, iff any time is INVALID_ABSTIME + * + * output parameter: + * i_start, i_end: interval margins + * + * Time interval: + * `[' {` '} `'' `'' {` '} `'' `'' {` '} `]' + * + * OR `Undefined Range' (see also INVALID_INTERVAL_STR) + * + * where satisfies the syntax of absolute time. + * + * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970'] + */ +static int +istinterval(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end) +{ + char *p, + *p1; + char c; + + p = i_string; + /* skip leading blanks up to '[' */ + while ((c = *p) != '\0') + { + if (IsSpace(c)) + p++; + else if (c != '[') + return 0; /* syntax error */ + else + break; + } + p++; + /* skip leading blanks up to "'" */ + while ((c = *p) != '\0') + { + if (IsSpace(c)) + p++; + else if (c != '"') + return 0; /* syntax error */ + else + break; + } + p++; + if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0) + return 0; /* undefined range, handled like a syntax + * err. */ + /* search for the end of the first date and change it to a NULL */ + p1 = p; + while ((c = *p1) != '\0') + { + if (c == '"') + { + *p1 = '\0'; + break; + } + p1++; + } + /* get the first date */ + *i_start = nabstimein(p); /* first absolute date */ + /* rechange NULL at the end of the first date to a "'" */ + *p1 = '"'; + p = ++p1; + /* skip blanks up to "'", beginning of second date */ + while ((c = *p) != '\0') + { + if (IsSpace(c)) + p++; + else if (c != '"') + return 0; /* syntax error */ + else + break; + } + p++; + /* search for the end of the second date and change it to a NULL */ + p1 = p; + while ((c = *p1) != '\0') + { + if (c == '"') + { + *p1 = '\0'; + break; + } + p1++; + } + /* get the second date */ + *i_end = nabstimein(p); /* second absolute date */ + /* rechange NULL at the end of the first date to a ''' */ + *p1 = '"'; + p = ++p1; + /* skip blanks up to ']' */ + while ((c = *p) != '\0') + { + if (IsSpace(c)) + p++; + else if (c != ']') + return 0; /* syntax error */ + else + break; + } + p++; + c = *p; + if (c != '\0') + return 0; /* syntax error */ + /* it seems to be a valid interval */ + return 1; +} + + +/***************************************************************************** + * + *****************************************************************************/ + +int32 /* RelativeTime */ +int4reltime(int32 timevalue) +{ + return timevalue; +} + +/* + * timeofday - + * returns the current time as a text. similar to timenow() but returns + * seconds with more precision (up to microsecs). (I need this to compare + * the Wisconsin benchmark with Illustra whose TimeNow() shows current + * time with precision up to microsecs.) - ay 3/95 + */ +text * +timeofday(void) +{ + + struct timeval tp; + struct timezone tpz; + char templ[500]; + char buf[500]; + text *tm; + int len = 0; + + gettimeofday(&tp, &tpz); + strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z", + localtime((time_t *) &tp.tv_sec)); + sprintf(buf, templ, tp.tv_usec); + + len = VARHDRSZ + strlen(buf); + tm = (text *) palloc(len); + VARSIZE(tm) = len; + strncpy(VARDATA(tm), buf, strlen(buf)); + return tm; +} diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index cdbac4c7f1..77202c8308 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1,114 +1,2210 @@ -#include +/*------------------------------------------------------------------------- + * + * timestamp.c + * Functions for the built-in SQL92 type "timestamp" and "interval". + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.22 2000/02/16 17:24:48 thomas Exp $ + * + *------------------------------------------------------------------------- + */ #include +#include +#include +#include #include "postgres.h" -#include "access/xact.h" +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef USE_POSIX_TIME +#include +#endif + #include "miscadmin.h" #include "utils/builtins.h" -time_t -timestamp_in(const char *timestamp_str) -{ - int4 result; - result = nabstimein((char *) timestamp_str); +#if 0 + + +static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); +static int DecodeNumber(int flen, char *field, + int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); +static int DecodeNumberField(int len, char *str, + int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); +static int DecodeSpecial(int field, char *lowtoken, int *val); +static int DecodeTime(char *str, int fmask, int *tmask, + struct tm * tm, double *fsec); +static int DecodeTimezone(char *str, int *tzp); +static int DecodeUnits(int field, char *lowtoken, int *val); +static int EncodeSpecialTimestamp(Timestamp dt, char *str); +static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); +static Timestamp dt2local(Timestamp dt, int timezone); +static int j2day(int jd); +static double time2t(const int hour, const int min, const double sec); +static int interval2tm(Interval span, struct tm * tm, float8 *fsec); +static int tm2interval(struct tm * tm, double fsec, Interval *span); + + +#define USE_DATE_CACHE 1 +#define ROUND_ALL 0 + +int day_tab[2][13] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, +{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}; + + +char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", +"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; + +char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", +"Thursday", "Friday", "Saturday", NULL}; + +/* TMODULO() + * Macro to replace modf(), which is broken on some platforms. + */ +#define TMODULO(t,q,u) \ +do { \ + q = ((t < 0)? ceil(t / u): floor(t / u)); \ + if (q != 0) \ + t -= rint(q * u); \ +} while(0) + +static void GetEpochTime(struct tm * tm); + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#endif + + +static double time2t(const int hour, const int min, const double sec); + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* timestamp_in() + * Convert a string to internal form. + */ +Timestamp * +timestamp_in(char *str) +{ + Timestamp *result; + + double fsec; + struct tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) timestamp external representation"); + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) + elog(ERROR, "Bad timestamp external representation '%s'", str); + + result = palloc(sizeof(Timestamp)); + + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "Timestamp out of range '%s'", str); + break; + + case DTK_EPOCH: + TIMESTAMP_EPOCH(*result); + break; + + case DTK_CURRENT: + TIMESTAMP_CURRENT(*result); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(*result); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(*result); + break; + + case DTK_INVALID: + TIMESTAMP_INVALID(*result); + break; + + default: + elog(ERROR, "Internal coding error, can't input timestamp '%s'", str); + } return result; -} +} /* timestamp_in() */ +/* timestamp_out() + * Convert a timestamp to external form. + */ char * -timestamp_out(time_t timestamp) +timestamp_out(Timestamp *dt) { char *result; int tz; - double fsec = 0; struct tm tt, *tm = &tt; + double fsec; + char *tzn; char buf[MAXDATELEN + 1]; - char zone[MAXDATELEN + 1], - *tzn = zone; - switch (timestamp) + if (!PointerIsValid(dt)) + return NULL; + + if (TIMESTAMP_IS_RESERVED(*dt)) { - case EPOCH_ABSTIME: - strcpy(buf, EPOCH); - break; - case INVALID_ABSTIME: - strcpy(buf, INVALID); - break; - case CURRENT_ABSTIME: - strcpy(buf, DCURRENT); - break; - case NOEND_ABSTIME: - strcpy(buf, LATE); - break; - case NOSTART_ABSTIME: - strcpy(buf, EARLY); - break; - default: - abstime2tm(timestamp, &tz, tm, tzn); - EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf); - break; + EncodeSpecialTimestamp(*dt, buf); + } + else if (timestamp2tm(*dt, &tz, tm, &fsec, &tzn) == 0) + { + EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); + + } + else + EncodeSpecialTimestamp(DT_INVALID, buf); result = palloc(strlen(buf) + 1); + strcpy(result, buf); + return result; } /* timestamp_out() */ -time_t + +/* interval_in() + * Convert a string to internal form. + * + * External format(s): + * Uses the generic date/time parsing and decoding routines. + */ +Interval * +interval_in(char *str) +{ + Interval *span; + + double fsec; + struct tm tt, + *tm = &tt; + int dtype; + int nf; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + tm->tm_year = 0; + tm->tm_mon = 0; + tm->tm_mday = 0; + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + fsec = 0; + + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) interval external representation"); + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) + elog(ERROR, "Bad interval external representation '%s'", str); + + span = palloc(sizeof(Interval)); + + switch (dtype) + { + case DTK_DELTA: + if (tm2interval(tm, fsec, span) != 0) + { +#if NOT_USED + INTERVAL_INVALID(span); +#endif + elog(ERROR, "Bad interval external representation '%s'", str); + } + break; + + default: + elog(ERROR, "Internal coding error, can't input interval '%s'", str); + } + + return span; +} /* interval_in() */ + +/* interval_out() + * Convert a time span to external form. + */ +char * +interval_out(Interval *span) +{ + char *result; + + struct tm tt, + *tm = &tt; + double fsec; + char buf[MAXDATELEN + 1]; + + if (!PointerIsValid(span)) + return NULL; + + if (interval2tm(*span, tm, &fsec) != 0) + return NULL; + + if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0) + elog(ERROR, "Unable to format interval"); + + result = palloc(strlen(buf) + 1); + + strcpy(result, buf); + return result; +} /* interval_out() */ + + +/* EncodeSpecialTimestamp() + * Convert reserved timestamp data type to string. + */ +int +EncodeSpecialTimestamp(Timestamp dt, char *str) +{ + if (TIMESTAMP_IS_RESERVED(dt)) + { + if (TIMESTAMP_IS_INVALID(dt)) + strcpy(str, INVALID); + else if (TIMESTAMP_IS_NOBEGIN(dt)) + strcpy(str, EARLY); + else if (TIMESTAMP_IS_NOEND(dt)) + strcpy(str, LATE); + else if (TIMESTAMP_IS_CURRENT(dt)) + strcpy(str, DCURRENT); + else if (TIMESTAMP_IS_EPOCH(dt)) + strcpy(str, EPOCH); + else + strcpy(str, INVALID); + return TRUE; + } + + return FALSE; +} /* EncodeSpecialTimestamp() */ + +Timestamp * now(void) { - time_t sec; + Timestamp *result; + AbsoluteTime sec; + + result = palloc(sizeof(Timestamp)); sec = GetCurrentTransactionStartTime(); - return sec; + + *result = (sec - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400)); + + return result; } +void +dt2time(Timestamp jd, int *hour, int *min, double *sec) +{ + double time; + + time = jd; + + *hour = (time / 3600); + time -= ((*hour) * 3600); + *min = (time / 60); + time -= ((*min) * 60); + *sec = JROUND(time); + + return; +} /* dt2time() */ + + +/* timestamp2tm() + * Convert timestamp data type to POSIX time structure. + * Note that year is _not_ 1900-based, but is an explicit full value. + * Also, month is one-based, _not_ zero-based. + * Returns: + * 0 on success + * -1 on out of range + * + * For dates within the system-supported time_t range, convert to the + * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 + */ +int +timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn) +{ + double date, + date0, + time, + sec; + time_t utime; + +#ifdef USE_POSIX_TIME + struct tm *tx; + +#endif + + date0 = date2j(2000, 1, 1); + + time = dt; + TMODULO(time, date, 86400e0); + + if (time < 0) + { + time += 86400; + date -= 1; + } + + /* Julian day routine does not work for negative Julian days */ + if (date < -date0) + return -1; + + /* add offset to go from J2000 back to standard Julian date */ + date += date0; + + j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + dt2time(time, &tm->tm_hour, &tm->tm_min, &sec); + + *fsec = JROUND(sec); + TMODULO(*fsec, tm->tm_sec, 1e0); + + if (tzp != NULL) + { + if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + { + utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400); + +#ifdef USE_POSIX_TIME + tx = localtime(&utime); + tm->tm_year = tx->tm_year + 1900; + tm->tm_mon = tx->tm_mon + 1; + tm->tm_mday = tx->tm_mday; + tm->tm_hour = tx->tm_hour; + tm->tm_min = tx->tm_min; +#if NOT_USED +/* XXX HACK + * Argh! My Linux box puts in a 1 second offset for dates less than 1970 + * but only if the seconds field was non-zero. So, don't copy the seconds + * field and instead carry forward from the original - tgl 97/06/18 + * Note that GNU/Linux uses the standard freeware zic package as do + * many other platforms so this may not be GNU/Linux/ix86-specific. + */ + tm->tm_sec = tx->tm_sec; +#endif + tm->tm_isdst = tx->tm_isdst; + +#if defined(HAVE_TM_ZONE) + tm->tm_gmtoff = tx->tm_gmtoff; + tm->tm_zone = tx->tm_zone; + + *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ + if (tzn != NULL) + *tzn = (char *) tm->tm_zone; +#elif defined(HAVE_INT_TIMEZONE) +#ifdef __CYGWIN__ + *tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone); +#else + *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone); +#endif + if (tzn != NULL) + *tzn = tzname[(tm->tm_isdst > 0)]; +#else +#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined +#endif + +#else /* !USE_POSIX_TIME */ + *tzp = CTimeZone; /* V7 conventions; don't know timezone? */ + if (tzn != NULL) + *tzn = CTZName; +#endif + + } + else + { + *tzp = 0; + tm->tm_isdst = 0; + if (tzn != NULL) + *tzn = NULL; + } + + dt = dt2local(dt, *tzp); + + } + else + { + tm->tm_isdst = 0; + if (tzn != NULL) + *tzn = NULL; + } + + return 0; +} /* timestamp2tm() */ + + +/* tm2timestamp() + * Convert a tm structure to a timestamp data type. + * Note that year is _not_ 1900-based, but is an explicit full value. + * Also, month is one-based, _not_ zero-based. + */ +int +tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result) +{ + + double date, + time; + + /* Julian day routines are not correct for negative Julian days */ + if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) + return -1; + + date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); + time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec)); + *result = (date * 86400 + time); + if (tzp != NULL) + *result = dt2local(*result, -(*tzp)); + + return 0; +} /* tm2timestamp() */ + + +/* interval2tm() + * Convert a interval data type to a tm structure. + */ +int +interval2tm(Interval span, struct tm * tm, float8 *fsec) +{ + double time; + + if (span.month != 0) + { + tm->tm_year = span.month / 12; + tm->tm_mon = span.month % 12; + + } + else + { + tm->tm_year = 0; + tm->tm_mon = 0; + } + +#ifdef ROUND_ALL + time = JROUND(span.time); +#else + time = span.time; +#endif + + TMODULO(time, tm->tm_mday, 86400e0); + TMODULO(time, tm->tm_hour, 3600e0); + TMODULO(time, tm->tm_min, 60e0); + TMODULO(time, tm->tm_sec, 1e0); + *fsec = time; + + return 0; +} /* interval2tm() */ + +int +tm2interval(struct tm * tm, double fsec, Interval *span) +{ + span->month = ((tm->tm_year * 12) + tm->tm_mon); + span->time = ((((((tm->tm_mday * 24.0) + + tm->tm_hour) * 60.0) + + tm->tm_min) * 60.0) + + tm->tm_sec); + span->time = JROUND(span->time + fsec); + + return 0; +} /* tm2interval() */ + +static double +time2t(const int hour, const int min, const double sec) +{ + return (((hour * 60) + min) * 60) + sec; +} /* time2t() */ + +Timestamp +dt2local(Timestamp dt, int tz) +{ + dt -= tz; + dt = JROUND(dt); + return dt; +} /* dt2local() */ + + +/***************************************************************************** + * PUBLIC ROUTINES * + *****************************************************************************/ + + bool -timestampeq(time_t t1, time_t t2) +timestamp_finite(Timestamp *timestamp) { - return abstimeeq(t1, t2); -} + if (!PointerIsValid(timestamp)) + return FALSE; + + return !TIMESTAMP_NOT_FINITE(*timestamp); +} /* timestamp_finite() */ bool -timestampne(time_t t1, time_t t2) +interval_finite(Interval *interval) { - return abstimene(t1, t2); -} + if (!PointerIsValid(interval)) + return FALSE; + + return !INTERVAL_NOT_FINITE(*interval); +} /* interval_finite() */ + + +/*---------------------------------------------------------- + * Relational operators for timestamp. + *---------------------------------------------------------*/ + +static void +GetEpochTime(struct tm * tm) +{ + struct tm *t0; + time_t epoch = 0; + + t0 = gmtime(&epoch); + + tm->tm_year = t0->tm_year; + tm->tm_mon = t0->tm_mon; + tm->tm_mday = t0->tm_mday; + tm->tm_hour = t0->tm_hour; + tm->tm_min = t0->tm_min; + tm->tm_sec = t0->tm_sec; + + if (tm->tm_year < 1900) + tm->tm_year += 1900; + tm->tm_mon++; + + return; +} /* GetEpochTime() */ + +Timestamp +SetTimestamp(Timestamp dt) +{ + struct tm tt; + + if (TIMESTAMP_IS_CURRENT(dt)) + { + GetCurrentTime(&tt); + tm2timestamp(&tt, 0, NULL, &dt); + dt = dt2local(dt, -CTimeZone); + } + else + { /* if (TIMESTAMP_IS_EPOCH(dt1)) */ + GetEpochTime(&tt); + tm2timestamp(&tt, 0, NULL, &dt); + } + + return dt; +} /* SetTimestamp() */ + +/* timestamp_relop - is timestamp1 relop timestamp2 + */ +bool +timestamp_eq(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 == dt2; +} /* timestamp_eq() */ bool -timestamplt(time_t t1, time_t t2) +timestamp_ne(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimelt(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 != dt2; +} /* timestamp_ne() */ bool -timestampgt(time_t t1, time_t t2) +timestamp_lt(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimegt(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 < dt2; +} /* timestamp_lt() */ bool -timestample(time_t t1, time_t t2) +timestamp_gt(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimele(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 > dt2; +} /* timestamp_gt() */ bool -timestampge(time_t t1, time_t t2) +timestamp_le(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimege(t1, t2); -} + Timestamp dt1, + dt2; -DateTime * -timestamp_datetime(time_t timestamp) -{ - return abstime_datetime((AbsoluteTime) timestamp); -} /* timestamp_datetime() */ + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; -time_t -datetime_timestamp(DateTime *datetime) + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 <= dt2; +} /* timestamp_le() */ + +bool +timestamp_ge(Timestamp *timestamp1, Timestamp *timestamp2) { - return (AbsoluteTime) datetime_abstime(datetime); -} /* datetime_timestamp() */ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 >= dt2; +} /* timestamp_ge() */ + + +/* timestamp_cmp - 3-state comparison for timestamp + * collate invalid timestamp at the end + */ +int +timestamp_cmp(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return 0; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1)) + { + return (TIMESTAMP_IS_INVALID(dt2) ? 0 : 1); + + } + else if (TIMESTAMP_IS_INVALID(dt2)) + { + return -1; + + } + else + { + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + } + + return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0)); +} /* timestamp_cmp() */ + + +/* interval_relop - is interval1 relop interval2 + */ +bool +interval_eq(Interval *interval1, Interval *interval2) +{ + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + return ((interval1->time == interval2->time) + && (interval1->month == interval2->month)); +} /* interval_eq() */ + +bool +interval_ne(Interval *interval1, Interval *interval2) +{ + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + return ((interval1->time != interval2->time) + || (interval1->month != interval2->month)); +} /* interval_ne() */ + +bool +interval_lt(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 < span2; +} /* interval_lt() */ + +bool +interval_gt(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 > span2; +} /* interval_gt() */ + +bool +interval_le(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 <= span2; +} /* interval_le() */ + +bool +interval_ge(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 >= span2; +} /* interval_ge() */ + + +/* interval_cmp - 3-state comparison for interval + */ +int +interval_cmp(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return 0; + + if (INTERVAL_IS_INVALID(*interval1)) + { + return INTERVAL_IS_INVALID(*interval2) ? 0 : 1; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + return -1; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return (span1 < span2) ? -1 : (span1 > span2) ? 1 : 0; +} /* interval_cmp() */ + + +/*---------------------------------------------------------- + * "Arithmetic" operators on date/times. + * timestamp_foo returns foo as an object (pointer) that + * can be passed between languages. + * timestamp_xx is an internal routine which returns the + * actual value. + *---------------------------------------------------------*/ + +Timestamp * +timestamp_smaller(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1)) + *result = dt2; + else if (TIMESTAMP_IS_INVALID(dt2)) + *result = dt1; + else + *result = ((dt2 < dt1) ? dt2 : dt1); + + return result; +} /* timestamp_smaller() */ + +Timestamp * +timestamp_larger(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1)) + *result = dt2; + else if (TIMESTAMP_IS_INVALID(dt2)) + *result = dt1; + else + *result = ((dt2 > dt1) ? dt2 : dt1); + + return result; +} /* timestamp_larger() */ + + +Interval * +timestamp_mi(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Interval *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Interval)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1) + || TIMESTAMP_IS_INVALID(dt2)) + { + TIMESTAMP_INVALID(result->time); + + } + else + result->time = JROUND(dt1 - dt2); + result->month = 0; + + return result; +} /* timestamp_mi() */ + + +/* timestamp_pl_span() + * Add a interval to a timestamp data type. + * Note that interval has provisions for qualitative year/month + * units, so try to do the right thing with them. + * To add a month, increment the month, and use the same day of month. + * Then, if the next month has fewer days, set the day of month + * to the last day of month. + * Lastly, add in the "quantitative time". + */ +Timestamp * +timestamp_pl_span(Timestamp *timestamp, Interval *span) +{ + Timestamp *result; + Timestamp dt; + int tz; + char *tzn; + + if ((!PointerIsValid(timestamp)) || (!PointerIsValid(span))) + return NULL; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { + *result = *timestamp; + + } + else if (INTERVAL_IS_INVALID(*span)) + { + TIMESTAMP_INVALID(*result); + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if (span->month != 0) + { + struct tm tt, + *tm = &tt; + double fsec; + + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0) + { + tm->tm_mon += span->month; + if (tm->tm_mon > 12) + { + tm->tm_year += ((tm->tm_mon - 1) / 12); + tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); + } + else if (tm->tm_mon < 1) + { + tm->tm_year += ((tm->tm_mon / 12) - 1); + tm->tm_mon = ((tm->tm_mon % 12) + 12); + } + + /* adjust for end of month boundary problems... */ + if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) + tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); + + if (tm2timestamp(tm, fsec, &tz, &dt) != 0) + elog(ERROR, "Unable to add timestamp and interval"); + + } + else + TIMESTAMP_INVALID(dt); + } + +#ifdef ROUND_ALL + dt = JROUND(dt + span->time); +#else + dt += span->time; +#endif + + *result = dt; + } + + return result; +} /* timestamp_pl_span() */ + +Timestamp * +timestamp_mi_span(Timestamp *timestamp, Interval *span) +{ + Timestamp *result; + Interval tspan; + + if (!PointerIsValid(timestamp) || !PointerIsValid(span)) + return NULL; + + tspan.month = -span->month; + tspan.time = -span->time; + + result = timestamp_pl_span(timestamp, &tspan); + + return result; +} /* timestamp_mi_span() */ + + +Interval * +interval_um(Interval *interval) +{ + Interval *result; + + if (!PointerIsValid(interval)) + return NULL; + + result = palloc(sizeof(Interval)); + + result->time = -(interval->time); + result->month = -(interval->month); + + return result; +} /* interval_um() */ + + +Interval * +interval_smaller(Interval *interval1, Interval *interval2) +{ + Interval *result; + + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return NULL; + + result = palloc(sizeof(Interval)); + + if (INTERVAL_IS_INVALID(*interval1)) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + { + result->time = interval1->time; + result->month = interval1->month; + + } + else + { + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + if (span2 < span1) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else + { + result->time = interval1->time; + result->month = interval1->month; + } + } + + return result; +} /* interval_smaller() */ + +Interval * +interval_larger(Interval *interval1, Interval *interval2) +{ + Interval *result; + + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return NULL; + + result = palloc(sizeof(Interval)); + + if (INTERVAL_IS_INVALID(*interval1)) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + { + result->time = interval1->time; + result->month = interval1->month; + + } + else + { + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + if (span2 > span1) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else + { + result->time = interval1->time; + result->month = interval1->month; + } + } + + return result; +} /* interval_larger() */ + + +Interval * +interval_pl(Interval *span1, Interval *span2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) + return NULL; + + result = palloc(sizeof(Interval)); + + result->month = (span1->month + span2->month); + result->time = JROUND(span1->time + span2->time); + + return result; +} /* interval_pl() */ + +Interval * +interval_mi(Interval *span1, Interval *span2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) + return NULL; + + result = palloc(sizeof(Interval)); + + result->month = (span1->month - span2->month); + result->time = JROUND(span1->time - span2->time); + + return result; +} /* interval_mi() */ + +Interval * +interval_div(Interval *span1, float8 *arg2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2))) + return NULL; + + if (!PointerIsValid(result = palloc(sizeof(Interval)))) + elog(ERROR, "Memory allocation failed, can't divide intervals"); + + if (*arg2 == 0.0) + elog(ERROR, "interval_div: divide by 0.0 error"); + + result->month = rint(span1->month / *arg2); + result->time = JROUND(span1->time / *arg2); + + return result; +} /* interval_div() */ + +/* timestamp_age() + * Calculate time difference while retaining year/month fields. + * Note that this does not result in an accurate absolute time span + * since year and month are out of context once the arithmetic + * is done. + */ +Interval * +timestamp_age(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Interval *result; + + Timestamp dt1, + dt2; + double fsec, + fsec1, + fsec2; + struct tm tt, + *tm = &tt; + struct tm tt1, + *tm1 = &tt1; + struct tm tt2, + *tm2 = &tt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + result = palloc(sizeof(Interval)); + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1) + || TIMESTAMP_IS_INVALID(dt2)) + { + TIMESTAMP_INVALID(result->time); + + } + else if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) + && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) + { + fsec = (fsec1 - fsec2); + tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); + tm->tm_min = (tm1->tm_min - tm2->tm_min); + tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); + tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); + tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); + tm->tm_year = (tm1->tm_year - tm2->tm_year); + + /* flip sign if necessary... */ + if (dt1 < dt2) + { + fsec = -fsec; + tm->tm_sec = -tm->tm_sec; + tm->tm_min = -tm->tm_min; + tm->tm_hour = -tm->tm_hour; + tm->tm_mday = -tm->tm_mday; + tm->tm_mon = -tm->tm_mon; + tm->tm_year = -tm->tm_year; + } + + if (tm->tm_sec < 0) + { + tm->tm_sec += 60; + tm->tm_min--; + } + + if (tm->tm_min < 0) + { + tm->tm_min += 60; + tm->tm_hour--; + } + + if (tm->tm_hour < 0) + { + tm->tm_hour += 24; + tm->tm_mday--; + } + + if (tm->tm_mday < 0) + { + if (dt1 < dt2) + { + tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1]; + tm->tm_mon--; + } + else + { + tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1]; + tm->tm_mon--; + } + } + + if (tm->tm_mon < 0) + { + tm->tm_mon += 12; + tm->tm_year--; + } + + /* recover sign if necessary... */ + if (dt1 < dt2) + { + fsec = -fsec; + tm->tm_sec = -tm->tm_sec; + tm->tm_min = -tm->tm_min; + tm->tm_hour = -tm->tm_hour; + tm->tm_mday = -tm->tm_mday; + tm->tm_mon = -tm->tm_mon; + tm->tm_year = -tm->tm_year; + } + + if (tm2interval(tm, fsec, result) != 0) + elog(ERROR, "Unable to decode timestamp"); + + } + else + elog(ERROR, "Unable to decode timestamp"); + + return result; +} /* timestamp_age() */ + + +/*---------------------------------------------------------- + * Conversion operators. + *---------------------------------------------------------*/ + + +/* timestamp_text() + * Convert timestamp to text data type. + */ +text * +timestamp_text(Timestamp *timestamp) +{ + text *result; + char *str; + int len; + + if (!PointerIsValid(timestamp)) + return NULL; + + str = timestamp_out(timestamp); + + if (!PointerIsValid(str)) + return NULL; + + len = (strlen(str) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), str, (len - VARHDRSZ)); + + pfree(str); + + return result; +} /* timestamp_text() */ + + +/* text_timestamp() + * Convert text string to timestamp. + * Text type is not null terminated, so use temporary string + * then call the standard input routine. + */ +Timestamp * +text_timestamp(text *str) +{ + Timestamp *result; + int i; + char *sp, + *dp, + dstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return NULL; + + sp = VARDATA(str); + dp = dstr; + for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) + *dp++ = *sp++; + *dp = '\0'; + + result = timestamp_in(dstr); + + return result; +} /* text_timestamp() */ + + +/* interval_text() + * Convert interval to text data type. + */ +text * +interval_text(Interval *interval) +{ + text *result; + char *str; + int len; + + if (!PointerIsValid(interval)) + return NULL; + + str = interval_out(interval); + + if (!PointerIsValid(str)) + return NULL; + + len = (strlen(str) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), str, (len - VARHDRSZ)); + + pfree(str); + + return result; +} /* interval_text() */ + + +/* text_interval() + * Convert text string to interval. + * Text type may not be null terminated, so copy to temporary string + * then call the standard input routine. + */ +Interval * +text_interval(text *str) +{ + Interval *result; + int i; + char *sp, + *dp, + dstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return NULL; + + sp = VARDATA(str); + dp = dstr; + for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) + *dp++ = *sp++; + *dp = '\0'; + + result = interval_in(dstr); + + return result; +} /* text_interval() */ + +/* timestamp_trunc() + * Extract specified field from timestamp. + */ +Timestamp * +timestamp_trunc(text *units, Timestamp *timestamp) +{ + Timestamp *result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + char *tzn; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(timestamp))) + return NULL; + + result = palloc(sizeof(Timestamp)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { +#if NOT_USED +/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ + elog(ERROR, "Timestamp is not finite", NULL); +#endif + *result = 0; + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)) + { + switch (val) + { + case DTK_MILLENIUM: + tm->tm_year = (tm->tm_year / 1000) * 1000; + case DTK_CENTURY: + tm->tm_year = (tm->tm_year / 100) * 100; + case DTK_DECADE: + tm->tm_year = (tm->tm_year / 10) * 10; + case DTK_YEAR: + tm->tm_mon = 1; + case DTK_QUARTER: + tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1; + case DTK_MONTH: + tm->tm_mday = 1; + case DTK_DAY: + tm->tm_hour = 0; + case DTK_HOUR: + tm->tm_min = 0; + case DTK_MINUTE: + tm->tm_sec = 0; + case DTK_SECOND: + fsec = 0; + break; + + case DTK_MILLISEC: + fsec = rint(fsec * 1000) / 1000; + break; + + case DTK_MICROSEC: + fsec = rint(fsec * 1000000) / 1000000; + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + result = NULL; + } + + if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + { +#ifdef USE_POSIX_TIME + tm->tm_isdst = -1; + tm->tm_year -= 1900; + tm->tm_mon -= 1; + tm->tm_isdst = -1; + mktime(tm); + tm->tm_year += 1900; + tm->tm_mon += 1; + +#if defined(HAVE_TM_ZONE) + tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ +#elif defined(HAVE_INT_TIMEZONE) + +#ifdef __CYGWIN__ + tz = (tm->tm_isdst ? (_timezone - 3600) : _timezone); +#else + tz = (tm->tm_isdst ? (timezone - 3600) : timezone); +#endif + +#else +#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined +#endif + +#else /* !USE_POSIX_TIME */ + tz = CTimeZone; +#endif + } + else + { + tm->tm_isdst = 0; + tz = 0; + } + + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits); + +#if NOT_USED + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + TIMESTAMP_EPOCH(*result); + *result = dt - SetTimestamp(*result); +#endif + + } + else + { + elog(ERROR, "Timestamp units '%s' not recognized", lowunits); + result = NULL; + } + } + + return result; +} /* timestamp_trunc() */ + +/* interval_trunc() + * Extract specified field from interval. + */ +Interval * +interval_trunc(text *units, Interval *interval) +{ + Interval *result; + + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(interval))) + return NULL; + + result = palloc(sizeof(Interval)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + + if (INTERVAL_IS_INVALID(*interval)) + { +#if NOT_USED + elog(ERROR, "Interval is not finite", NULL); +#endif + result = NULL; + + } + else if (type == UNITS) + { + + if (interval2tm(*interval, tm, &fsec) == 0) + { + switch (val) + { + case DTK_MILLENIUM: + tm->tm_year = (tm->tm_year / 1000) * 1000; + case DTK_CENTURY: + tm->tm_year = (tm->tm_year / 100) * 100; + case DTK_DECADE: + tm->tm_year = (tm->tm_year / 10) * 10; + case DTK_YEAR: + tm->tm_mon = 0; + case DTK_QUARTER: + tm->tm_mon = (3 * (tm->tm_mon / 4)); + case DTK_MONTH: + tm->tm_mday = 0; + case DTK_DAY: + tm->tm_hour = 0; + case DTK_HOUR: + tm->tm_min = 0; + case DTK_MINUTE: + tm->tm_sec = 0; + case DTK_SECOND: + fsec = 0; + break; + + case DTK_MILLISEC: + fsec = rint(fsec * 1000) / 1000; + break; + + case DTK_MICROSEC: + fsec = rint(fsec * 1000000) / 1000000; + break; + + default: + elog(ERROR, "Interval units '%s' not supported", lowunits); + result = NULL; + } + + if (tm2interval(tm, fsec, result) != 0) + elog(ERROR, "Unable to truncate interval to '%s'", lowunits); + + } + else + { + elog(NOTICE, "Interval out of range"); + result = NULL; + } + +#if NOT_USED + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + *result = interval->time; + if (interval->month != 0) + { + *result += ((365.25 * 86400) * (interval->month / 12)); + *result += ((30 * 86400) * (interval->month % 12)); + } +#endif + + } + else + { + elog(ERROR, "Interval units '%s' not recognized", textout(units)); + result = NULL; + } + + return result; +} /* interval_trunc() */ + + +/* timestamp_part() + * Extract specified field from timestamp. + */ +float64 +timestamp_part(text *units, Timestamp *timestamp) +{ + float64 result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double dummy; + double fsec; + char *tzn; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(timestamp))) + return NULL; + + result = palloc(sizeof(float64data)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + if (type == IGNORE) + type = DecodeSpecial(0, lowunits, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { +#if NOT_USED +/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ + elog(ERROR, "Timestamp is not finite", NULL); +#endif + *result = 0; + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)) + { + switch (val) + { + case DTK_TZ: + *result = tz; + break; + + case DTK_TZ_MINUTE: + *result = tz / 60; + TMODULO(*result, dummy, 60e0); + break; + + case DTK_TZ_HOUR: + dummy = tz; + TMODULO(dummy, *result, 3600e0); + break; + + case DTK_MICROSEC: + *result = (fsec * 1000000); + break; + + case DTK_MILLISEC: + *result = (fsec * 1000); + break; + + case DTK_SECOND: + *result = (tm->tm_sec + fsec); + break; + + case DTK_MINUTE: + *result = tm->tm_min; + break; + + case DTK_HOUR: + *result = tm->tm_hour; + break; + + case DTK_DAY: + *result = tm->tm_mday; + break; + + case DTK_MONTH: + *result = tm->tm_mon; + break; + + case DTK_QUARTER: + *result = (tm->tm_mon / 4) + 1; + break; + + case DTK_YEAR: + *result = tm->tm_year; + break; + + case DTK_DECADE: + *result = (tm->tm_year / 10); + break; + + case DTK_CENTURY: + *result = (tm->tm_year / 100); + break; + + case DTK_MILLENIUM: + *result = (tm->tm_year / 1000); + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + *result = 0; + } + + } + else if (type == RESERV) + { + switch (val) + { + case DTK_EPOCH: + TIMESTAMP_EPOCH(*result); + *result = dt - SetTimestamp(*result); + break; + + case DTK_DOW: + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to encode timestamp"); + + *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); + break; + + case DTK_DOY: + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to encode timestamp"); + + *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + - date2j(tm->tm_year, 1, 1) + 1); + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + *result = 0; + } + + } + else + { + elog(ERROR, "Timestamp units '%s' not recognized", lowunits); + *result = 0; + } + } + + return result; +} /* timestamp_part() */ + + +/* interval_part() + * Extract specified field from interval. + */ +float64 +interval_part(text *units, Interval *interval) +{ + float64 result; + + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(interval))) + return NULL; + + result = palloc(sizeof(float64data)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + if (type == IGNORE) + type = DecodeSpecial(0, lowunits, &val); + + if (INTERVAL_IS_INVALID(*interval)) + { +#if NOT_USED + elog(ERROR, "Interval is not finite"); +#endif + *result = 0; + + } + else if (type == UNITS) + { + + if (interval2tm(*interval, tm, &fsec) == 0) + { + switch (val) + { + case DTK_MICROSEC: + *result = (fsec * 1000000); + break; + + case DTK_MILLISEC: + *result = (fsec * 1000); + break; + + case DTK_SECOND: + *result = (tm->tm_sec + fsec); + break; + + case DTK_MINUTE: + *result = tm->tm_min; + break; + + case DTK_HOUR: + *result = tm->tm_hour; + break; + + case DTK_DAY: + *result = tm->tm_mday; + break; + + case DTK_MONTH: + *result = tm->tm_mon; + break; + + case DTK_QUARTER: + *result = (tm->tm_mon / 4) + 1; + break; + + case DTK_YEAR: + *result = tm->tm_year; + break; + + case DTK_DECADE: + *result = (tm->tm_year / 10); + break; + + case DTK_CENTURY: + *result = (tm->tm_year / 100); + break; + + case DTK_MILLENIUM: + *result = (tm->tm_year / 1000); + break; + + default: + elog(ERROR, "Interval units '%s' not yet supported", textout(units)); + result = NULL; + } + + } + else + { + elog(NOTICE, "Interval out of range"); + *result = 0; + } + + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + *result = interval->time; + if (interval->month != 0) + { + *result += ((365.25 * 86400) * (interval->month / 12)); + *result += ((30 * 86400) * (interval->month % 12)); + } + + } + else + { + elog(ERROR, "Interval units '%s' not recognized", textout(units)); + *result = 0; + } + + return result; +} /* interval_part() */ + + +/* timestamp_zone() + * Encode timestamp type with specified time zone. + */ +text * +timestamp_zone(text *zone, Timestamp *timestamp) +{ + text *result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowzone[MAXDATELEN + 1]; + char *tzn, + upzone[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + char buf[MAXDATELEN + 1]; + int len; + + if ((!PointerIsValid(zone)) || (!PointerIsValid(timestamp))) + return NULL; + + up = VARDATA(zone); + lp = lowzone; + for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeSpecial(0, lowzone, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { + + /* + * could return null but Postgres doesn't like that currently. - + * tgl 97/06/12 + */ + elog(ERROR, "Timestamp is not finite"); + result = NULL; + + } + else if ((type == TZ) || (type == DTZ)) + { + tm->tm_isdst = ((type == DTZ) ? 1 : 0); + tz = val * 60; + + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + dt = dt2local(dt, tz); + + if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0) + elog(ERROR, "Timestamp not legal"); + + up = upzone; + lp = lowzone; + for (i = 0; *lp != '\0'; i++) + *up++ = toupper(*lp++); + *up = '\0'; + + tzn = upzone; + EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); + + len = (strlen(buf) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), buf, (len - VARHDRSZ)); + + } + else + { + elog(ERROR, "Time zone '%s' not recognized", lowzone); + result = NULL; + } + + return result; +} /* timestamp_zone() */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index bf93830ca2..482b299c55 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.14 2000/02/15 20:49:23 tgl Exp $ + * $Id: catversion.h,v 1.15 2000/02/16 17:26:06 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200002151 +#define CATALOG_VERSION_NO 200002161 #endif diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 7376e3ee72..67c761e369 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_aggregate.h,v 1.22 2000/01/26 05:57:56 momjian Exp $ + * $Id: pg_aggregate.h,v 1.23 2000/02/16 17:26:06 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -95,7 +95,7 @@ DATA(insert OID = 0 ( avg PGUID int2pl int2inc int2div 21 21 21 21 _nul DATA(insert OID = 0 ( avg PGUID float4pl float4inc float4div 700 700 700 700 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID float8pl float8inc float8div 701 701 701 701 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID cash_pl float8inc cash_div_flt8 790 790 701 790 _null_ 0.0 )); -DATA(insert OID = 0 ( avg PGUID timespan_pl float8inc timespan_div 1186 1186 701 1186 _null_ 0.0 )); +DATA(insert OID = 0 ( avg PGUID interval_pl float8inc interval_div 1186 1186 701 1186 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID numeric_add numeric_inc numeric_div 1700 1700 1700 1700 _null_ 0 )); DATA(insert OID = 0 ( sum PGUID int8pl - - 20 20 0 20 _null_ _null_ )); @@ -104,7 +104,7 @@ DATA(insert OID = 0 ( sum PGUID int2pl - - 21 21 0 21 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID float4pl - - 700 700 0 700 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID float8pl - - 701 701 0 701 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID cash_pl - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( sum PGUID timespan_pl - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( sum PGUID interval_pl - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID numeric_add - - 1700 1700 0 1700 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID int8larger - - 20 20 0 20 _null_ _null_ )); @@ -115,8 +115,8 @@ DATA(insert OID = 0 ( max PGUID float8larger - - 701 701 0 701 _null_ _null_ DATA(insert OID = 0 ( max PGUID int4larger - - 702 702 0 702 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID date_larger - - 1082 1082 0 1082 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID cashlarger - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( max PGUID datetime_larger - - 1184 1184 0 1184 _null_ _null_ )); -DATA(insert OID = 0 ( max PGUID timespan_larger - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( max PGUID timestamp_larger - - 1184 1184 0 1184 _null_ _null_ )); +DATA(insert OID = 0 ( max PGUID interval_larger - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID text_larger - - 25 25 0 25 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID numeric_larger - - 1700 1700 0 1700 _null_ _null_ )); @@ -128,8 +128,8 @@ DATA(insert OID = 0 ( min PGUID float8smaller - - 701 701 0 701 _null_ _null DATA(insert OID = 0 ( min PGUID int4smaller - - 702 702 0 702 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID date_smaller - - 1082 1082 0 1082 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID cashsmaller - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( min PGUID datetime_smaller - - 1184 1184 0 1184 _null_ _null_ )); -DATA(insert OID = 0 ( min PGUID timespan_smaller - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( min PGUID timestamp_smaller - - 1184 1184 0 1184 _null_ _null_ )); +DATA(insert OID = 0 ( min PGUID interval_smaller - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID text_smaller - - 25 25 0 25 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID numeric_smaller - - 1700 1700 0 1700 _null_ _null_ )); diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index f33c6894af..c036ef5eac 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_opclass.h,v 1.28 2000/02/10 19:51:45 momjian Exp $ + * $Id: pg_opclass.h,v 1.29 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -106,9 +106,9 @@ DATA(insert OID = 1115 ( time_ops 1083 )); DESCR(""); DATA(insert OID = 1181 ( name_ops 19 )); DESCR(""); -DATA(insert OID = 1312 ( datetime_ops 1184 )); +DATA(insert OID = 1312 ( timestamp_ops 1184 )); DESCR(""); -DATA(insert OID = 1313 ( timespan_ops 1186 )); +DATA(insert OID = 1313 ( interval_ops 1186 )); DESCR(""); DATA(insert OID = 810 ( macaddr_ops 829 )); DESCR(""); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index fd33b4b510..e510c621d0 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.67 2000/02/10 19:51:45 momjian Exp $ + * $Id: pg_operator.h,v 1.68 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -244,18 +244,18 @@ DATA(insert OID = 568 ( "<" PGUID 0 b t f 703 703 16 569 571 0 0 reltimelt DATA(insert OID = 569 ( ">" PGUID 0 b t f 703 703 16 568 570 0 0 reltimegt scalargtsel scalargtjoinsel )); DATA(insert OID = 570 ( "<=" PGUID 0 b t f 703 703 16 571 569 0 0 reltimele scalarltsel scalarltjoinsel )); DATA(insert OID = 571 ( ">=" PGUID 0 b t f 703 703 16 570 568 0 0 reltimege scalargtsel scalargtjoinsel )); -DATA(insert OID = 572 ( "~=" PGUID 0 b t f 704 704 16 572 0 0 0 intervalsame eqsel eqjoinsel )); -DATA(insert OID = 573 ( "<<" PGUID 0 b t f 704 704 16 0 0 0 0 intervalct - - )); -DATA(insert OID = 574 ( "&&" PGUID 0 b t f 704 704 16 0 0 0 0 intervalov - - )); -DATA(insert OID = 575 ( "#=" PGUID 0 b t f 704 703 16 0 576 0 0 intervalleneq - - )); -DATA(insert OID = 576 ( "#<>" PGUID 0 b t f 704 703 16 0 575 0 0 intervallenne - - )); -DATA(insert OID = 577 ( "#<" PGUID 0 b t f 704 703 16 0 580 0 0 intervallenlt - - )); -DATA(insert OID = 578 ( "#>" PGUID 0 b t f 704 703 16 0 579 0 0 intervallengt - - )); -DATA(insert OID = 579 ( "#<=" PGUID 0 b t f 704 703 16 0 578 0 0 intervallenle - - )); -DATA(insert OID = 580 ( "#>=" PGUID 0 b t f 704 703 16 0 577 0 0 intervallenge - - )); +DATA(insert OID = 572 ( "~=" PGUID 0 b t f 704 704 16 572 0 0 0 tintervalsame eqsel eqjoinsel )); +DATA(insert OID = 573 ( "<<" PGUID 0 b t f 704 704 16 0 0 0 0 tintervalct - - )); +DATA(insert OID = 574 ( "&&" PGUID 0 b t f 704 704 16 0 0 0 0 tintervalov - - )); +DATA(insert OID = 575 ( "#=" PGUID 0 b t f 704 703 16 0 576 0 0 tintervalleneq - - )); +DATA(insert OID = 576 ( "#<>" PGUID 0 b t f 704 703 16 0 575 0 0 tintervallenne - - )); +DATA(insert OID = 577 ( "#<" PGUID 0 b t f 704 703 16 0 580 0 0 tintervallenlt - - )); +DATA(insert OID = 578 ( "#>" PGUID 0 b t f 704 703 16 0 579 0 0 tintervallengt - - )); +DATA(insert OID = 579 ( "#<=" PGUID 0 b t f 704 703 16 0 578 0 0 tintervallenle - - )); +DATA(insert OID = 580 ( "#>=" PGUID 0 b t f 704 703 16 0 577 0 0 tintervallenge - - )); DATA(insert OID = 581 ( "+" PGUID 0 b t f 702 703 702 0 0 0 0 timepl - - )); DATA(insert OID = 582 ( "-" PGUID 0 b t f 702 703 702 0 0 0 0 timemi - - )); -DATA(insert OID = 583 ( "" PGUID 0 b t f 702 704 16 0 0 0 0 ininterval - - )); +DATA(insert OID = 583 ( "" PGUID 0 b t f 702 704 16 0 0 0 0 intinterval - - )); DATA(insert OID = 584 ( "-" PGUID 0 l t f 0 700 700 0 0 0 0 float4um - - )); DATA(insert OID = 585 ( "-" PGUID 0 l t f 0 701 701 0 0 0 0 float8um - - )); DATA(insert OID = 586 ( "+" PGUID 0 b t f 700 700 700 586 0 0 0 float4pl - - )); @@ -274,7 +274,7 @@ DATA(insert OID = 598 ( "%" PGUID 0 l t f 0 701 701 0 0 0 0 dtrunc DATA(insert OID = 599 ( "%" PGUID 0 r t f 701 0 701 0 0 0 0 dround - - )); DATA(insert OID = 1282 ( ":" PGUID 0 l t f 0 701 701 0 0 0 0 dexp - - )); DATA(insert OID = 1283 ( ";" PGUID 0 l t f 0 701 701 0 0 0 0 dlog1 - - )); -DATA(insert OID = 1284 ( "|" PGUID 0 l t f 0 704 702 0 0 0 0 intervalstart - - )); +DATA(insert OID = 1284 ( "|" PGUID 0 l t f 0 704 702 0 0 0 0 tintervalstart - - )); DATA(insert OID = 606 ( "<#>" PGUID 0 b t f 702 702 704 0 0 0 0 mktinterval - - )); DATA(insert OID = 607 ( "=" PGUID 0 b t t 26 26 16 607 608 609 609 oideq eqsel eqjoinsel )); #define MIN_OIDCMP 607 /* used by cache code */ @@ -399,12 +399,12 @@ DATA(insert OID = 807 ( "/" PGUID 0 b t f 603 600 603 0 0 0 0 box_div DATA(insert OID = 808 ( "?-" PGUID 0 b t f 600 600 16 808 0 0 0 point_horiz - - )); DATA(insert OID = 809 ( "?|" PGUID 0 b t f 600 600 16 809 0 0 0 point_vert - - )); -DATA(insert OID = 811 ( "=" PGUID 0 b t f 704 704 16 811 812 0 0 intervaleq eqsel eqjoinsel )); -DATA(insert OID = 812 ( "<>" PGUID 0 b t f 704 704 16 812 811 0 0 intervalne neqsel neqjoinsel )); -DATA(insert OID = 813 ( "<" PGUID 0 b t f 704 704 16 814 816 0 0 intervallt scalarltsel scalarltjoinsel )); -DATA(insert OID = 814 ( ">" PGUID 0 b t f 704 704 16 813 815 0 0 intervalgt scalargtsel scalargtjoinsel )); -DATA(insert OID = 815 ( "<=" PGUID 0 b t f 704 704 16 816 814 0 0 intervalle scalarltsel scalarltjoinsel )); -DATA(insert OID = 816 ( ">=" PGUID 0 b t f 704 704 16 815 813 0 0 intervalge scalargtsel scalargtjoinsel )); +DATA(insert OID = 811 ( "=" PGUID 0 b t f 704 704 16 811 812 0 0 tintervaleq eqsel eqjoinsel )); +DATA(insert OID = 812 ( "<>" PGUID 0 b t f 704 704 16 812 811 0 0 tintervalne neqsel neqjoinsel )); +DATA(insert OID = 813 ( "<" PGUID 0 b t f 704 704 16 814 816 0 0 tintervallt scalarltsel scalarltjoinsel )); +DATA(insert OID = 814 ( ">" PGUID 0 b t f 704 704 16 813 815 0 0 tintervalgt scalargtsel scalargtjoinsel )); +DATA(insert OID = 815 ( "<=" PGUID 0 b t f 704 704 16 816 814 0 0 tintervalle scalarltsel scalarltjoinsel )); +DATA(insert OID = 816 ( ">=" PGUID 0 b t f 704 704 16 815 813 0 0 tintervalge scalargtsel scalargtjoinsel )); DATA(insert OID = 843 ( "*" PGUID 0 b t f 790 700 790 845 0 0 0 cash_mul_flt4 - - )); DATA(insert OID = 844 ( "/" PGUID 0 b t f 790 700 790 0 0 0 0 cash_div_flt4 - - )); @@ -536,37 +536,30 @@ DATA(insert OID = 1234 ( "~*" PGUID 0 b t f 1042 25 16 0 1235 0 0 texticreg #define OID_BPCHAR_ICREGEXEQ_OP 1234 DATA(insert OID = 1235 ( "!~*" PGUID 0 b t f 1042 25 16 0 1234 0 0 texticregexne neqsel neqjoinsel )); -DATA(insert OID = 1300 ( "=" PGUID 0 b t t 1296 1296 16 1300 1301 1302 1302 timestampeq eqsel eqjoinsel )); -DATA(insert OID = 1301 ( "<>" PGUID 0 b t f 1296 1296 16 1301 1300 0 0 timestampne neqsel neqjoinsel )); -DATA(insert OID = 1302 ( "<" PGUID 0 b t f 1296 1296 16 1303 1305 0 0 timestamplt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1303 ( ">" PGUID 0 b t f 1296 1296 16 1302 1304 0 0 timestampgt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1304 ( "<=" PGUID 0 b t f 1296 1296 16 1305 1303 0 0 timestample scalarltsel scalarltjoinsel )); -DATA(insert OID = 1305 ( ">=" PGUID 0 b t f 1296 1296 16 1304 1302 0 0 timestampge scalargtsel scalargtjoinsel )); - -/* datetime operators */ +/* timestamp operators */ /* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */ -DATA(insert OID = 1320 ( "=" PGUID 0 b t f 1184 1184 16 1320 1321 1322 1322 datetime_eq eqsel eqjoinsel )); -DATA(insert OID = 1321 ( "<>" PGUID 0 b t f 1184 1184 16 1321 1320 0 0 datetime_ne neqsel neqjoinsel )); -DATA(insert OID = 1322 ( "<" PGUID 0 b t f 1184 1184 16 1324 1325 0 0 datetime_lt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1323 ( "<=" PGUID 0 b t f 1184 1184 16 1325 1324 0 0 datetime_le scalarltsel scalarltjoinsel )); -DATA(insert OID = 1324 ( ">" PGUID 0 b t f 1184 1184 16 1322 1323 0 0 datetime_gt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1325 ( ">=" PGUID 0 b t f 1184 1184 16 1323 1322 0 0 datetime_ge scalargtsel scalargtjoinsel )); +DATA(insert OID = 1320 ( "=" PGUID 0 b t f 1184 1184 16 1320 1321 1322 1322 timestamp_eq eqsel eqjoinsel )); +DATA(insert OID = 1321 ( "<>" PGUID 0 b t f 1184 1184 16 1321 1320 0 0 timestamp_ne neqsel neqjoinsel )); +DATA(insert OID = 1322 ( "<" PGUID 0 b t f 1184 1184 16 1324 1325 0 0 timestamp_lt scalarltsel scalarltjoinsel )); +DATA(insert OID = 1323 ( "<=" PGUID 0 b t f 1184 1184 16 1325 1324 0 0 timestamp_le scalarltsel scalarltjoinsel )); +DATA(insert OID = 1324 ( ">" PGUID 0 b t f 1184 1184 16 1322 1323 0 0 timestamp_gt scalargtsel scalargtjoinsel )); +DATA(insert OID = 1325 ( ">=" PGUID 0 b t f 1184 1184 16 1323 1322 0 0 timestamp_ge scalargtsel scalargtjoinsel )); -DATA(insert OID = 1327 ( "+" PGUID 0 b t f 1184 1186 1184 0 0 0 0 datetime_pl_span - - )); -DATA(insert OID = 1328 ( "-" PGUID 0 b t f 1184 1184 1186 0 0 0 0 datetime_mi - - )); -DATA(insert OID = 1329 ( "-" PGUID 0 b t f 1184 1186 1184 0 0 0 0 datetime_mi_span - - )); +DATA(insert OID = 1327 ( "+" PGUID 0 b t f 1184 1186 1184 0 0 0 0 timestamp_pl_span - - )); +DATA(insert OID = 1328 ( "-" PGUID 0 b t f 1184 1184 1186 0 0 0 0 timestamp_mi - - )); +DATA(insert OID = 1329 ( "-" PGUID 0 b t f 1184 1186 1184 0 0 0 0 timestamp_mi_span - - )); -/* timespan operators */ -DATA(insert OID = 1330 ( "=" PGUID 0 b t f 1186 1186 16 1330 1331 1332 1332 timespan_eq eqsel eqjoinsel )); -DATA(insert OID = 1331 ( "<>" PGUID 0 b t f 1186 1186 16 1331 1330 0 0 timespan_ne neqsel neqjoinsel )); -DATA(insert OID = 1332 ( "<" PGUID 0 b t f 1186 1186 16 1334 1335 0 0 timespan_lt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1333 ( "<=" PGUID 0 b t f 1186 1186 16 1335 1334 0 0 timespan_le scalarltsel scalarltjoinsel )); -DATA(insert OID = 1334 ( ">" PGUID 0 b t f 1186 1186 16 1332 1333 0 0 timespan_gt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1335 ( ">=" PGUID 0 b t f 1186 1186 16 1333 1332 0 0 timespan_ge scalargtsel scalargtjoinsel )); +/* interval operators */ +DATA(insert OID = 1330 ( "=" PGUID 0 b t f 1186 1186 16 1330 1331 1332 1332 interval_eq eqsel eqjoinsel )); +DATA(insert OID = 1331 ( "<>" PGUID 0 b t f 1186 1186 16 1331 1330 0 0 interval_ne neqsel neqjoinsel )); +DATA(insert OID = 1332 ( "<" PGUID 0 b t f 1186 1186 16 1334 1335 0 0 interval_lt scalarltsel scalarltjoinsel )); +DATA(insert OID = 1333 ( "<=" PGUID 0 b t f 1186 1186 16 1335 1334 0 0 interval_le scalarltsel scalarltjoinsel )); +DATA(insert OID = 1334 ( ">" PGUID 0 b t f 1186 1186 16 1332 1333 0 0 interval_gt scalargtsel scalargtjoinsel )); +DATA(insert OID = 1335 ( ">=" PGUID 0 b t f 1186 1186 16 1333 1332 0 0 interval_ge scalargtsel scalargtjoinsel )); -DATA(insert OID = 1336 ( "-" PGUID 0 l t f 0 1186 1186 0 0 0 0 timespan_um - - )); -DATA(insert OID = 1337 ( "+" PGUID 0 b t f 1186 1186 1186 1337 0 0 0 timespan_pl - - )); -DATA(insert OID = 1338 ( "-" PGUID 0 b t f 1186 1186 1186 0 0 0 0 timespan_mi - - )); +DATA(insert OID = 1336 ( "-" PGUID 0 l t f 0 1186 1186 0 0 0 0 interval_um - - )); +DATA(insert OID = 1337 ( "+" PGUID 0 b t f 1186 1186 1186 1337 0 0 0 interval_pl - - )); +DATA(insert OID = 1338 ( "-" PGUID 0 b t f 1186 1186 1186 0 0 0 0 interval_mi - - )); /* additional geometric operators - thomas 97/04/18 */ DATA(insert OID = 1420 ( "@@" PGUID 0 l t f 0 718 600 0 0 0 0 circle_center - - )); @@ -626,7 +619,7 @@ DATA(insert OID = 1567 ( "##" PGUID 0 b t f 601 603 600 0 0 0 0 close_s DATA(insert OID = 1568 ( "##" PGUID 0 b t f 628 603 600 0 0 0 0 close_lb - - )); DATA(insert OID = 1577 ( "##" PGUID 0 b t f 628 601 600 0 0 0 0 close_ls - - )); DATA(insert OID = 1578 ( "##" PGUID 0 b t f 601 601 600 0 0 0 0 close_lseg - - )); -DATA(insert OID = 1585 ( "/" PGUID 0 b t f 1186 701 1186 0 0 0 0 timespan_div - - )); +DATA(insert OID = 1585 ( "/" PGUID 0 b t f 1186 701 1186 0 0 0 0 interval_div - - )); DATA(insert OID = 1586 ( "<>" PGUID 0 b t f 601 601 16 1586 1535 0 0 lseg_ne neqsel neqjoinsel )); DATA(insert OID = 1587 ( "<" PGUID 0 b t f 601 601 16 1589 1590 0 0 lseg_lt - - )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 87107b1df3..64c015fbff 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.121 2000/02/15 20:49:23 tgl Exp $ + * $Id: pg_proc.h,v 1.122 2000/02/16 17:26:07 thomas Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -517,9 +517,9 @@ DATA(insert OID = 246 ( tintervalin PGUID 11 f t f 1 f 704 "0" 100 0 0 100 DESCR("(internal)"); DATA(insert OID = 247 ( tintervalout PGUID 11 f t f 1 f 23 "0" 100 0 0 100 tintervalout - )); DESCR("(internal)"); -DATA(insert OID = 248 ( ininterval PGUID 11 f t f 2 f 16 "702 704" 100 0 0 100 ininterval - )); +DATA(insert OID = 248 ( intinterval PGUID 11 f t f 2 f 16 "702 704" 100 0 0 100 intinterval - )); DESCR("abstime in tinterval"); -DATA(insert OID = 249 ( intervalrel PGUID 11 f t f 1 f 703 "704" 100 0 0 100 intervalrel - )); +DATA(insert OID = 249 ( tintervalrel PGUID 11 f t f 1 f 703 "704" 100 0 0 100 tintervalrel - )); DESCR(""); DATA(insert OID = 250 ( timenow PGUID 11 f t f 0 f 702 "0" 100 0 0 100 timenow - )); DESCR("Current date and time"); @@ -547,27 +547,27 @@ DATA(insert OID = 261 ( reltimele PGUID 11 f t t 2 f 16 "703 703" 100 0 0 1 DESCR("less-than-or-equal"); DATA(insert OID = 262 ( reltimege PGUID 11 f t t 2 f 16 "703 703" 100 0 0 100 reltimege - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 263 ( intervalsame PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalsame - )); +DATA(insert OID = 263 ( tintervalsame PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalsame - )); DESCR("same as"); -DATA(insert OID = 264 ( intervalct PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalct - )); +DATA(insert OID = 264 ( tintervalct PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalct - )); DESCR("less-than"); -DATA(insert OID = 265 ( intervalov PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalov - )); +DATA(insert OID = 265 ( tintervalov PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalov - )); DESCR("overlaps"); -DATA(insert OID = 266 ( intervalleneq PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervalleneq - )); +DATA(insert OID = 266 ( tintervalleneq PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervalleneq - )); DESCR("length equal"); -DATA(insert OID = 267 ( intervallenne PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenne - )); +DATA(insert OID = 267 ( tintervallenne PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenne - )); DESCR("length not equal to"); -DATA(insert OID = 268 ( intervallenlt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenlt - )); +DATA(insert OID = 268 ( tintervallenlt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenlt - )); DESCR("length less-than"); -DATA(insert OID = 269 ( intervallengt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallengt - )); +DATA(insert OID = 269 ( tintervallengt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallengt - )); DESCR("length greater-than"); -DATA(insert OID = 270 ( intervallenle PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenle - )); +DATA(insert OID = 270 ( tintervallenle PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenle - )); DESCR("length less-than-or-equal"); -DATA(insert OID = 271 ( intervallenge PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenge - )); +DATA(insert OID = 271 ( tintervallenge PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenge - )); DESCR("length greater-than-or-equal"); -DATA(insert OID = 272 ( intervalstart PGUID 11 f t f 1 f 702 "704" 100 0 0 100 intervalstart - )); +DATA(insert OID = 272 ( tintervalstart PGUID 11 f t f 1 f 702 "704" 100 0 0 100 tintervalstart - )); DESCR("start of interval"); -DATA(insert OID = 273 ( intervalend PGUID 11 f t f 1 f 702 "704" 100 0 0 100 intervalend - )); +DATA(insert OID = 273 ( tintervalend PGUID 11 f t f 1 f 702 "704" 100 0 0 100 tintervalend - )); DESCR(""); DATA(insert OID = 274 ( timeofday PGUID 11 f t f 0 f 25 "0" 100 0 0 100 timeofday - )); DESCR("Current date and time with microseconds"); @@ -920,7 +920,7 @@ DATA(insert OID = 669 ( varchar PGUID 11 f t t 2 f 1043 "1043 23" 100 0 0 1 DESCR("truncate varchar()"); DATA(insert OID = 676 ( mktinterval PGUID 11 f t f 2 f 704 "702 702" 100 0 0 100 mktinterval - )); -DESCR("convert to interval"); +DESCR("convert to tinterval"); DATA(insert OID = 619 ( oidvectorne PGUID 11 f t t 2 f 16 "30 30" 100 0 0 100 oidvectorne - )); DESCR("less-than"); DATA(insert OID = 677 ( oidvectorlt PGUID 11 f t t 2 f 16 "30 30" 100 0 0 100 oidvectorlt - )); @@ -1052,17 +1052,17 @@ DESCR("gist(internal)"); DATA(insert OID = 782 ( gistbuild PGUID 11 f t f 9 f 23 "0" 100 0 0 100 gistbuild - )); DESCR("gist(internal)"); -DATA(insert OID = 784 ( intervaleq PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervaleq - )); +DATA(insert OID = 784 ( tintervaleq PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervaleq - )); DESCR("equal"); -DATA(insert OID = 785 ( intervalne PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalne - )); +DATA(insert OID = 785 ( tintervalne PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalne - )); DESCR("not equal"); -DATA(insert OID = 786 ( intervallt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervallt - )); +DATA(insert OID = 786 ( tintervallt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervallt - )); DESCR("less-than"); -DATA(insert OID = 787 ( intervalgt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalgt - )); +DATA(insert OID = 787 ( tintervalgt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalgt - )); DESCR("greater-than"); -DATA(insert OID = 788 ( intervalle PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalle - )); +DATA(insert OID = 788 ( tintervalle PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalle - )); DESCR("less-than-or-equal"); -DATA(insert OID = 789 ( intervalge PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalge - )); +DATA(insert OID = 789 ( tintervalge PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalge - )); DESCR("greater-than-or-equal"); /* OIDS 800 - 899 */ @@ -1397,94 +1397,92 @@ DESCR("multiply"); DATA(insert OID = 1149 ( circle_div_pt PGUID 11 f t t 2 f 718 "718 600" 100 0 0 100 circle_div_pt - )); DESCR("divide"); -DATA(insert OID = 1150 ( datetime_in PGUID 11 f t f 1 f 1184 "0" 100 0 0 100 datetime_in - )); +DATA(insert OID = 1150 ( timestamp_in PGUID 11 f t f 1 f 1184 "0" 100 0 0 100 timestamp_in - )); DESCR("(internal)"); -DATA(insert OID = 1151 ( datetime_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 datetime_out - )); +DATA(insert OID = 1151 ( timestamp_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timestamp_out - )); DESCR("(internal)"); -DATA(insert OID = 1152 ( datetime_eq PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_eq - )); +DATA(insert OID = 1152 ( timestamp_eq PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_eq - )); DESCR("equal"); -DATA(insert OID = 1153 ( datetime_ne PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_ne - )); +DATA(insert OID = 1153 ( timestamp_ne PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_ne - )); DESCR("not equal"); -DATA(insert OID = 1154 ( datetime_lt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_lt - )); +DATA(insert OID = 1154 ( timestamp_lt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_lt - )); DESCR("less-than"); -DATA(insert OID = 1155 ( datetime_le PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_le - )); +DATA(insert OID = 1155 ( timestamp_le PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_le - )); DESCR("less-than-or-equal"); -DATA(insert OID = 1156 ( datetime_ge PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_ge - )); +DATA(insert OID = 1156 ( timestamp_ge PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_ge - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 1157 ( datetime_gt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_gt - )); +DATA(insert OID = 1157 ( timestamp_gt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_gt - )); DESCR("greater-than"); -DATA(insert OID = 1158 ( datetime_finite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 datetime_finite - )); +DATA(insert OID = 1158 ( timestamp_finite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 timestamp_finite - )); DESCR(""); -DATA(insert OID = 1159 ( datetime_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 datetime_zone - )); +DATA(insert OID = 1159 ( timestamp_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 timestamp_zone - )); DESCR(""); -DATA(insert OID = 1160 ( timespan_in PGUID 11 f t f 1 f 1186 "0" 100 0 0 100 timespan_in - )); +DATA(insert OID = 1160 ( interval_in PGUID 11 f t f 1 f 1186 "0" 100 0 0 100 interval_in - )); DESCR("(internal)"); -DATA(insert OID = 1161 ( timespan_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timespan_out - )); +DATA(insert OID = 1161 ( interval_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 interval_out - )); DESCR("(internal)"); -DATA(insert OID = 1162 ( timespan_eq PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_eq - )); +DATA(insert OID = 1162 ( interval_eq PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_eq - )); DESCR("equal"); -DATA(insert OID = 1163 ( timespan_ne PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_ne - )); +DATA(insert OID = 1163 ( interval_ne PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_ne - )); DESCR("not equal"); -DATA(insert OID = 1164 ( timespan_lt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_lt - )); +DATA(insert OID = 1164 ( interval_lt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_lt - )); DESCR("less-than"); -DATA(insert OID = 1165 ( timespan_le PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_le - )); +DATA(insert OID = 1165 ( interval_le PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_le - )); DESCR("less-than-or-equal"); -DATA(insert OID = 1166 ( timespan_ge PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_ge - )); +DATA(insert OID = 1166 ( interval_ge PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_ge - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 1167 ( timespan_gt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_gt - )); +DATA(insert OID = 1167 ( interval_gt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_gt - )); DESCR("greater-than"); -DATA(insert OID = 1168 ( timespan_um PGUID 11 f t f 1 f 1186 "1186" 100 0 0 100 timespan_um - )); +DATA(insert OID = 1168 ( interval_um PGUID 11 f t f 1 f 1186 "1186" 100 0 0 100 interval_um - )); DESCR("subtract"); -DATA(insert OID = 1169 ( timespan_pl PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_pl - )); +DATA(insert OID = 1169 ( interval_pl PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_pl - )); DESCR("addition"); -DATA(insert OID = 1170 ( timespan_mi PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_mi - )); +DATA(insert OID = 1170 ( interval_mi PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_mi - )); DESCR("subtract"); -DATA(insert OID = 1171 ( datetime_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 datetime_part - )); -DESCR("extract field from datetime"); -DATA(insert OID = 1172 ( timespan_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 timespan_part - )); -DESCR("extract field from timespan"); +DATA(insert OID = 1171 ( timestamp_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 timestamp_part - )); +DESCR("extract field from timestamp"); +DATA(insert OID = 1172 ( interval_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 interval_part - )); +DESCR("extract field from interval"); -DATA(insert OID = 1173 ( abstime_datetime PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_datetime - )); -DESCR("convert abstime to datetime"); -DATA(insert OID = 1174 ( date_datetime PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_datetime - )); -DESCR("convert date to datetime"); -DATA(insert OID = 1175 ( timestamp_datetime PGUID 11 f t f 1 f 1184 "1296" 100 0 0 100 timestamp_datetime - )); -DESCR("convert timestamp to datetime"); -DATA(insert OID = 1176 ( datetime_datetime PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_datetime - )); -DESCR("convert date and time to datetime"); -DATA(insert OID = 1177 ( reltime_timespan PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_timespan - )); -DESCR("convert reltime to timespan"); -DATA(insert OID = 1178 ( datetime_date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 datetime_date - )); -DESCR("convert datetime to date"); +DATA(insert OID = 1173 ( abstime_timestamp PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_timestamp - )); +DESCR("convert abstime to timestamp"); +DATA(insert OID = 1174 ( date_timestamp PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_timestamp - )); +DESCR("convert date to timestamp"); +DATA(insert OID = 1176 ( datetime_timestamp PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_timestamp - )); +DESCR("convert date and time to timestamp"); +DATA(insert OID = 1177 ( reltime_interval PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_interval - )); +DESCR("convert reltime to interval"); +DATA(insert OID = 1178 ( timestamp_date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 timestamp_date - )); +DESCR("convert timestamp to date"); DATA(insert OID = 1179 ( abstime_date PGUID 11 f t f 1 f 1082 "702" 100 0 0 100 abstime_date - )); DESCR("convert abstime to date"); -DATA(insert OID = 1180 ( datetime_abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 datetime_abstime - )); -DESCR("convert datetime to abstime"); +DATA(insert OID = 1180 ( timestamp_abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 timestamp_abstime - )); +DESCR("convert timestamp to abstime"); -DATA(insert OID = 1188 ( datetime_mi PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_mi - )); +DATA(insert OID = 1188 ( timestamp_mi PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_mi - )); DESCR("subtract"); -DATA(insert OID = 1189 ( datetime_pl_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 datetime_pl_span - )); +DATA(insert OID = 1189 ( timestamp_pl_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 timestamp_pl_span - )); DESCR("plus"); -DATA(insert OID = 1190 ( datetime_mi_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 datetime_mi_span - )); +DATA(insert OID = 1190 ( timestamp_mi_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 timestamp_mi_span - )); DESCR("minus"); -DATA(insert OID = 1191 ( text_datetime PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1192 ( datetime_text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 datetime_text - )); -DESCR("convert datetime to text"); -DATA(insert OID = 1193 ( timespan_text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 timespan_text - )); -DESCR("convert timespan to text"); -DATA(insert OID = 1194 ( timespan_reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 timespan_reltime - )); -DESCR("convert timespan to reltime"); -DATA(insert OID = 1195 ( datetime_smaller PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 datetime_smaller - )); +DATA(insert OID = 1191 ( text_timestamp PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_timestamp - )); +DESCR("convert text to timestamp"); +DATA(insert OID = 1192 ( timestamp_text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 timestamp_text - )); +DESCR("convert timestamp to text"); +DATA(insert OID = 1193 ( interval_text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 interval_text - )); +DESCR("convert interval to text"); +DATA(insert OID = 1194 ( interval_reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 interval_reltime - )); +DESCR("convert interval to reltime"); +DATA(insert OID = 1195 ( timestamp_smaller PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 timestamp_smaller - )); DESCR("smaller of two"); -DATA(insert OID = 1196 ( datetime_larger PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 datetime_larger - )); +DATA(insert OID = 1196 ( timestamp_larger PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 timestamp_larger - )); DESCR("larger of two"); -DATA(insert OID = 1197 ( timespan_smaller PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_smaller - )); +DATA(insert OID = 1197 ( interval_smaller PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_smaller - )); DESCR("smaller of two"); -DATA(insert OID = 1198 ( timespan_larger PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_larger - )); +DATA(insert OID = 1198 ( interval_larger PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_larger - )); DESCR("larger of two"); -DATA(insert OID = 1199 ( datetime_age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_age - )); +DATA(insert OID = 1199 ( timestamp_age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_age - )); DESCR("date difference preserving months and years"); /* OIDS 1200 - 1299 */ @@ -1492,10 +1490,10 @@ DESCR("date difference preserving months and years"); DATA(insert OID = 1200 ( int4reltime PGUID 11 f t t 1 f 703 "23" 100 0 0 100 int4reltime - )); DESCR("convert int4 to reltime"); -DATA(insert OID = 1217 ( datetime_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 datetime_trunc - )); -DESCR("truncate datetime to specified units"); -DATA(insert OID = 1218 ( timespan_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 timespan_trunc - )); -DESCR("truncate timespan to specified units"); +DATA(insert OID = 1217 ( timestamp_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 timestamp_trunc - )); +DESCR("truncate timestamp to specified units"); +DATA(insert OID = 1218 ( interval_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 interval_trunc - )); +DESCR("truncate interval to specified units"); DATA(insert OID = 1230 ( bpchar PGUID 11 f t t 1 f 1042 "18" 100 0 0 100 char_bpchar - )); DESCR("convert char to char()"); @@ -1523,9 +1521,9 @@ DESCR("character length"); DATA(insert OID = 1379 ( varcharoctetlen PGUID 11 f t t 1 f 23 "1043" 100 0 0 100 varcharoctetlen - )); DESCR("octet length"); -DATA(insert OID = 1263 ( text_timespan PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_timespan - )); -DESCR("convert text to timespan"); -DATA(insert OID = 1271 ( timespan_finite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 timespan_finite - )); +DATA(insert OID = 1263 ( text_interval PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_interval - )); +DESCR("convert text to interval"); +DATA(insert OID = 1271 ( interval_finite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 interval_finite - )); DESCR("boolean test"); DATA(insert OID = 1274 ( int84pl PGUID 11 f t t 2 f 20 "20 23" 100 0 0 100 int84pl - )); @@ -1562,44 +1560,26 @@ DESCR("latest tid of a tuple"); DATA(insert OID = 1294 ( currtid2 PGUID 11 f t f 2 f 27 "25 27" 100 0 0 100 currtid_byrelname - )); DESCR("latest tid of a tuple"); -DATA(insert OID = 1297 ( timestamp_in PGUID 11 f t f 1 f 1296 "0" 100 0 0 100 timestamp_in - )); -DESCR("(internal)"); -DATA(insert OID = 1298 ( timestamp_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timestamp_out - )); -DESCR("(internal)"); -DATA(insert OID = 1299 ( now PGUID 11 f t f 0 f 1296 "0" 100 0 0 100 now - )); +DATA(insert OID = 1299 ( now PGUID 11 f t f 0 f 1184 "0" 100 0 0 100 now - )); DESCR("current transaction time"); /* OIDS 1300 - 1399 */ -DATA(insert OID = 1306 ( timestampeq PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampeq - )); -DESCR("equal"); -DATA(insert OID = 1307 ( timestampne PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampne - )); -DESCR("not equal"); -DATA(insert OID = 1308 ( timestamplt PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestamplt - )); -DESCR("less-than"); -DATA(insert OID = 1309 ( timestampgt PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampgt - )); -DESCR("greater-than"); -DATA(insert OID = 1310 ( timestample PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestample - )); -DESCR("less-than-or-equal"); -DATA(insert OID = 1311 ( timestampge PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampge - )); -DESCR("greater-than-or-equal"); -DATA(insert OID = 1314 ( datetime_cmp PGUID 11 f t f 2 f 23 "1184 1184" 100 0 0 100 datetime_cmp - )); +DATA(insert OID = 1314 ( timestamp_cmp PGUID 11 f t f 2 f 23 "1184 1184" 100 0 0 100 timestamp_cmp - )); DESCR("less-equal-greater"); -DATA(insert OID = 1315 ( timespan_cmp PGUID 11 f t f 2 f 23 "1186 1186" 100 0 0 100 timespan_cmp - )); +DATA(insert OID = 1315 ( interval_cmp PGUID 11 f t f 2 f 23 "1186 1186" 100 0 0 100 interval_cmp - )); DESCR("less-equal-greater"); -DATA(insert OID = 1316 ( datetime_time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 datetime_time - )); -DESCR("convert datetime to time"); -DATA(insert OID = 1318 ( datetime_timestamp PGUID 11 f t f 1 f 1296 "1184" 100 0 0 100 datetime_timestamp - )); -DESCR("convert datetime to timestamp"); -DATA(insert OID = 1326 ( timespan_div PGUID 11 f t f 2 f 1186 "1186 701" 100 0 0 100 timespan_div - )); +DATA(insert OID = 1316 ( timestamp_time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 timestamp_time - )); +DESCR("convert timestamp to time"); +DATA(insert OID = 1326 ( interval_div PGUID 11 f t f 2 f 1186 "1186 701" 100 0 0 100 interval_div - )); DESCR("divide"); -DATA(insert OID = 1339 ( date_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 datetime_zone - )); +DATA(insert OID = 1339 ( date_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 timestamp_zone - )); DESCR(""); -DATA(insert OID = 1340 ( text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 datetime_text - )); -DESCR("convert datetime to text"); -DATA(insert OID = 1341 ( text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 timespan_text - )); -DESCR("convert timespan to text"); +DATA(insert OID = 1340 ( text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 timestamp_text - )); +DESCR("convert timestamp to text"); +DATA(insert OID = 1341 ( text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 interval_text - )); +DESCR("convert interval to text"); DATA(insert OID = 1342 ( text PGUID 11 f t t 1 f 25 "23" 100 0 0 100 int4_text - )); DESCR("convert int4 to text"); DATA(insert OID = 1343 ( text PGUID 11 f t t 1 f 25 "21" 100 0 0 100 int2_text - )); @@ -1617,48 +1597,42 @@ DESCR("get description for object id"); DATA(insert OID = 1349 ( oidvectortypes PGUID 11 f t f 1 f 25 "30" 100 0 0 100 oidvectortypes - )); DESCR("print type names of oidvector field"); -DATA(insert OID = 1350 ( datetime PGUID 14 f t f 1 f 1184 "1184" 100 0 0 100 "select $1" - )); +DATA(insert OID = 1350 ( timestamp PGUID 14 f t f 1 f 1184 "1184" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1351 ( datetime PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1352 ( datetime PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_datetime - )); -DESCR("convert abstime to datetime"); -DATA(insert OID = 1353 ( datetime PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_datetime - )); -DESCR("convert date to datetime"); -DATA(insert OID = 1354 ( datetime PGUID 11 f t f 1 f 1184 "1296" 100 0 0 100 timestamp_datetime - )); -DESCR("convert timestamp to datetime"); -DATA(insert OID = 1355 ( datetime PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_datetime - )); -DESCR("convert date and time to datetime"); -DATA(insert OID = 1356 ( timespan PGUID 14 f t t 1 f 1186 "1186" 100 0 0 100 "select $1" - )); +DATA(insert OID = 1351 ( timestamp PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_timestamp - )); +DESCR("convert text to timestamp"); +DATA(insert OID = 1352 ( timestamp PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_timestamp - )); +DESCR("convert abstime to timestamp"); +DATA(insert OID = 1353 ( timestamp PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_timestamp - )); +DESCR("convert date to timestamp"); +DATA(insert OID = 1355 ( timestamp PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_timestamp - )); +DESCR("convert date and time to timestamp"); +DATA(insert OID = 1356 ( interval PGUID 14 f t t 1 f 1186 "1186" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1357 ( timespan PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_timespan - )); -DESCR("convert reltime to timespan"); -DATA(insert OID = 1358 ( timespan PGUID 14 f t f 1 f 1186 "1083" 100 0 0 100 "select time_timespan($1)" - )); -DESCR("convert time to timespan"); +DATA(insert OID = 1357 ( interval PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_interval - )); +DESCR("convert reltime to interval"); +DATA(insert OID = 1358 ( interval PGUID 14 f t f 1 f 1186 "1083" 100 0 0 100 "select time_interval($1)" - )); +DESCR("convert time to interval"); DATA(insert OID = 1359 ( date PGUID 14 f t t 1 f 1082 "1082" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1360 ( date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 datetime_date - )); -DESCR("convert datetime to date"); +DATA(insert OID = 1360 ( date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 timestamp_date - )); +DESCR("convert timestamp to date"); DATA(insert OID = 1361 ( date PGUID 11 f t f 1 f 1082 "702" 100 0 0 100 abstime_date - )); DESCR("convert abstime to date"); DATA(insert OID = 1362 ( time PGUID 14 f t t 1 f 1083 "1083" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1363 ( time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 datetime_time - )); -DESCR("convert datetime to time"); -DATA(insert OID = 1364 ( time PGUID 14 f t f 1 f 1083 "702" 100 0 0 100 "select time(datetime($1))" - )); +DATA(insert OID = 1363 ( time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 timestamp_time - )); +DESCR("convert timestamp to time"); +DATA(insert OID = 1364 ( time PGUID 14 f t f 1 f 1083 "702" 100 0 0 100 "select time(timestamp($1))" - )); DESCR("convert abstime to time"); DATA(insert OID = 1365 ( abstime PGUID 14 f t f 1 f 702 "702" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1366 ( abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 datetime_abstime - )); -DESCR("convert datetime to abstime"); +DATA(insert OID = 1366 ( abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 timestamp_abstime - )); +DESCR("convert timestamp to abstime"); DATA(insert OID = 1367 ( reltime PGUID 14 f t t 1 f 703 "703" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1368 ( reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 timespan_reltime - )); -DESCR("convert timespan to reltime"); -DATA(insert OID = 1369 ( timestamp PGUID 14 f t t 1 f 1296 "1296" 100 0 0 100 "select $1" - )); -DESCR("convert (noop)"); -DATA(insert OID = 1370 ( timestamp PGUID 11 f t f 1 f 1296 "1184" 100 0 0 100 datetime_timestamp - )); -DESCR("convert datetime to timestamp"); +DATA(insert OID = 1368 ( reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 interval_reltime - )); +DESCR("convert interval to reltime"); DATA(insert OID = 1371 ( length PGUID 11 f t t 1 f 23 "25" 100 0 0 100 textlen - )); DESCR("character length"); DATA(insert OID = 1372 ( length PGUID 11 f t t 1 f 23 "1042" 100 0 0 100 bpcharlen - )); @@ -1673,36 +1647,36 @@ DESCR("octet length"); DATA(insert OID = 1376 ( octet_length PGUID 11 f t t 1 f 23 "1043" 100 0 0 100 varcharoctetlen - )); DESCR("octet length"); -DATA(insert OID = 1380 ( date_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 datetime_part - )); -DESCR("extract field from datetime"); -DATA(insert OID = 1381 ( date_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 timespan_part - )); -DESCR("extract field from timespan"); -DATA(insert OID = 1382 ( date_part PGUID 14 f t f 2 f 701 "25 702" 100 0 0 100 "select datetime_part($1, datetime($2))" - )); +DATA(insert OID = 1380 ( date_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 timestamp_part - )); +DESCR("extract field from timestamp"); +DATA(insert OID = 1381 ( date_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 interval_part - )); +DESCR("extract field from interval"); +DATA(insert OID = 1382 ( date_part PGUID 14 f t f 2 f 701 "25 702" 100 0 0 100 "select timestamp_part($1, timestamp($2))" - )); DESCR("extract field from abstime"); -DATA(insert OID = 1383 ( date_part PGUID 14 f t f 2 f 701 "25 703" 100 0 0 100 "select timespan_part($1, timespan($2))" - )); +DATA(insert OID = 1383 ( date_part PGUID 14 f t f 2 f 701 "25 703" 100 0 0 100 "select interval_part($1, interval($2))" - )); DESCR("extract field from reltime"); -DATA(insert OID = 1384 ( date_part PGUID 14 f t f 2 f 701 "25 1082" 100 0 0 100 "select datetime_part($1, datetime($2))" - )); +DATA(insert OID = 1384 ( date_part PGUID 14 f t f 2 f 701 "25 1082" 100 0 0 100 "select timestamp_part($1, timestamp($2))" - )); DESCR("extract field from date"); -DATA(insert OID = 1385 ( date_part PGUID 14 f t f 2 f 701 "25 1083" 100 0 0 100 "select timespan_part($1, timespan($2))" - )); +DATA(insert OID = 1385 ( date_part PGUID 14 f t f 2 f 701 "25 1083" 100 0 0 100 "select interval_part($1, interval($2))" - )); DESCR("extract field from time"); -DATA(insert OID = 1386 ( date_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 datetime_trunc - )); -DESCR("truncate datetime to field"); -DATA(insert OID = 1387 ( date_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 timespan_trunc - )); -DESCR("truncate timespan to field"); -DATA(insert OID = 1388 ( age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_age - )); -DESCR("difference between datetimes but leave years and months unresolved"); -DATA(insert OID = 1389 ( age PGUID 14 f t f 1 f 1186 "1184" 100 0 0 100 "select datetime_age(\'today\', $1)" - )); -DESCR("difference between datetime and today but leave years and months unresolved"); +DATA(insert OID = 1386 ( date_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 timestamp_trunc - )); +DESCR("truncate timestamp to field"); +DATA(insert OID = 1387 ( date_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 interval_trunc - )); +DESCR("truncate interval to field"); +DATA(insert OID = 1388 ( age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_age - )); +DESCR("difference between timestamps but leave years and months unresolved"); +DATA(insert OID = 1389 ( age PGUID 14 f t f 1 f 1186 "1184" 100 0 0 100 "select timestamp_age(\'today\', $1)" - )); +DESCR("difference between timestamp and today but leave years and months unresolved"); -DATA(insert OID = 1390 ( isfinite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 datetime_finite - )); +DATA(insert OID = 1390 ( isfinite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 timestamp_finite - )); DESCR("boolean test"); -DATA(insert OID = 1391 ( isfinite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 timespan_finite - )); +DATA(insert OID = 1391 ( isfinite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 interval_finite - )); DESCR("boolean test"); DATA(insert OID = 1392 ( isfinite PGUID 11 f t f 1 f 16 "702" 100 0 0 100 abstime_finite - )); DESCR("boolean test"); -DATA(insert OID = 1393 ( timespan PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_timespan - )); -DESCR("convert text to timespan"); +DATA(insert OID = 1393 ( interval PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_interval - )); +DESCR("convert text to interval"); DATA(insert OID = 1394 ( name PGUID 11 f t t 1 f 19 "25" 100 0 0 100 text_name - )); DESCR("convert text to name"); @@ -2352,9 +2326,7 @@ DATA(insert OID = 1769 ( numeric_cmp PGUID 11 f t t 2 f 23 "1700 1700" 100 0 0 DESCR("compare two numbers"); /* formatting */ -DATA(insert OID = 1770 ( to_char PGUID 11 f t f 2 f 25 "1184 25" 100 0 0 100 datetime_to_char - )); -DESCR("convert / formatting datetime to text"); -DATA(insert OID = 1771 ( to_char PGUID 11 f t f 2 f 25 "1296 25" 100 0 0 100 timestamp_to_char - )); +DATA(insert OID = 1770 ( to_char PGUID 11 f t f 2 f 25 "1184 25" 100 0 0 100 timestamp_to_char - )); DESCR("convert / formatting timestamp to text"); DATA(insert OID = 1772 ( to_char PGUID 11 f t f 2 f 25 "1700 25" 100 0 0 100 numeric_to_char - )); DESCR("convert / formatting numeric to text"); @@ -2368,10 +2340,8 @@ DATA(insert OID = 1776 ( to_char PGUID 11 f t f 2 f 25 "701 25" 100 0 0 100 DESCR("convert / formatting float8 to text"); DATA(insert OID = 1777 ( to_number PGUID 11 f t f 2 f 1700 "25 25" 100 0 0 100 numeric_to_number - )); DESCR("convert text to numeric"); -DATA(insert OID = 1778 ( to_datetime PGUID 11 f t f 2 f 1184 "25 25" 100 0 0 100 to_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1779 ( to_timestamp PGUID 11 f t f 2 f 1296 "25 25" 100 0 0 100 to_timestamp - )); -DESCR("convert text to datetime"); +DATA(insert OID = 1778 ( to_timestamp PGUID 11 f t f 2 f 1184 "25 25" 100 0 0 100 to_timestamp - )); +DESCR("convert text to timestamp"); DATA(insert OID = 1780 ( to_date PGUID 11 f t f 2 f 1082 "25 25" 100 0 0 100 to_date - )); DESCR("convert text to date"); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index b22c80e0f0..fa074460a7 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.80 2000/02/15 03:28:31 thomas Exp $ + * $Id: pg_type.h,v 1.81 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -370,20 +370,17 @@ DESCR("hh:mm:ss, ANSI SQL time"); /* OIDS 1100 - 1199 */ DATA(insert OID = 1182 ( _date PGUID -1 -1 f b t \054 0 1082 array_in array_out array_in array_out i _null_ )); DATA(insert OID = 1183 ( _time PGUID -1 -1 f b t \054 0 1083 array_in array_out array_in array_out d _null_ )); -DATA(insert OID = 1184 ( datetime PGUID 8 47 f b t \054 0 0 datetime_in datetime_out datetime_in datetime_out d _null_ )); +DATA(insert OID = 1184 ( timestamp PGUID 8 47 f b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out d _null_ )); DESCR("date and time"); -#define DATETIMEOID 1184 -DATA(insert OID = 1185 ( _datetime PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d _null_ )); -DATA(insert OID = 1186 ( timespan PGUID 12 47 f b t \054 0 0 timespan_in timespan_out timespan_in timespan_out d _null_ )); +#define TIMESTAMPOID 1184 +DATA(insert OID = 1185 ( _timestamp PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d _null_ )); +DATA(insert OID = 1186 ( interval PGUID 12 47 f b t \054 0 0 interval_in interval_out interval_in interval_out d _null_ )); DESCR("@ , time interval"); -#define TIMESPANOID 1186 -DATA(insert OID = 1187 ( _timespan PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d _null_ )); +#define INTERVALOID 1186 +DATA(insert OID = 1187 ( _interval PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d _null_ )); /* OIDS 1200 - 1299 */ DATA(insert OID = 1231 ( _numeric PGUID -1 -1 f b t \054 0 1700 array_in array_out array_in array_out i _null_ )); -DATA(insert OID = 1296 ( timestamp PGUID 4 19 t b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out i _null_ )); -DESCR("date time timezone, limited-range ISO-formated date and time"); -#define TIMESTAMPOID 1296 /* OIDS 1700 - 1799 */ DATA(insert OID = 1700 ( numeric PGUID -1 -1 f b t \054 0 0 numeric_in numeric_out numeric_in numeric_out i _null_ )); diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index bedaaa37bd..54107ef3b8 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_coerce.h,v 1.17 2000/01/26 05:58:27 momjian Exp $ + * $Id: parse_coerce.h,v 1.18 2000/02/16 17:26:16 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -48,8 +48,9 @@ typedef enum CATEGORY || ((t) == INT4OID) \ || ((t) == INT8OID) \ || ((t) == FLOAT8OID) \ - || ((t) == DATETIMEOID) \ + || ((t) == NUMERICOID) \ || ((t) == TIMESTAMPOID) \ + || ((t) == INTERVALOID) \ || ((t) == ABSTIMEOID) \ || ((t) == RELTIMEOID) \ || ((t) == CHAROID) \ @@ -70,8 +71,8 @@ typedef enum CATEGORY * Check for types with the same underlying binary representation. * This allows us to cheat and directly exchange values without * going through the trouble of calling a conversion function. - * Remove equivalencing of FLOAT8 and DATETIME. They really are not - * close enough in behavior, with the DATETIME reserved values + * Remove equivalencing of FLOAT8 and TIMESTAMP. They really are not + * close enough in behavior, with the TIMESTAMP reserved values * and special formatting. - thomas 1999-01-24 */ #define IS_BINARY_COMPATIBLE(a,b) \ @@ -87,12 +88,8 @@ typedef enum CATEGORY || ((a) == INT4OID && (b) == REGPROCOID) \ || ((a) == REGPROCOID && (b) == OIDOID) \ || ((a) == REGPROCOID && (b) == INT4OID) \ - || ((a) == ABSTIMEOID && (b) == TIMESTAMPOID) \ || ((a) == ABSTIMEOID && (b) == INT4OID) \ - || ((a) == TIMESTAMPOID && (b) == ABSTIMEOID) \ - || ((a) == TIMESTAMPOID && (b) == INT4OID) \ || ((a) == INT4OID && (b) == ABSTIMEOID) \ - || ((a) == INT4OID && (b) == TIMESTAMPOID) \ || ((a) == RELTIMEOID && (b) == INT4OID) \ || ((a) == INT4OID && (b) == RELTIMEOID) \ || ((a) == INETOID && (b) == CIDROID) \ @@ -104,21 +101,21 @@ typedef enum CATEGORY #define IS_HIGHER_TYPE(t) \ (((t) == TEXTOID) \ || ((t) == FLOAT8OID) \ - || ((t) == TIMESPANOID) \ - || ((t) == DATETIMEOID) \ + || ((t) == INTERVALOID) \ + || ((t) == TIMESTAMPOID) \ || ((t) == POLYGONOID) \ || ((t) == INETOID) ) /* IS_HIGHEST_TYPE() * These types are the most general in each of the type categories. - * Since timespan and datetime overload so many functions, let's - * give datetime the preference. + * Since interval and timestamp overload so many functions, let's + * give timestamp the preference. * Since text is a generic string type let's leave it out too. */ #define IS_HIGHEST_TYPE(t) \ (((t) == FLOAT8OID) \ - || ((t) == DATETIMEOID) \ - || ((t) == TIMESPANOID)) + || ((t) == TIMESTAMPOID) \ + || ((t) == INTERVALOID)) extern bool IsPreferredType(CATEGORY category, Oid type); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 7f9dcc6c46..df8dad8dc3 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.101 2000/02/15 20:49:27 tgl Exp $ + * $Id: builtins.h,v 1.102 2000/02/16 17:26:25 thomas Exp $ * * NOTES * This should normally only be included by fmgr.h. @@ -27,12 +27,14 @@ #include "nodes/relation.h" /* for amcostestimate parameters */ #include "storage/itemptr.h" #include "utils/array.h" -#include "utils/datetime.h" -#include "utils/geo_decls.h" #include "utils/inet.h" #include "utils/int8.h" -#include "utils/nabstime.h" +#include "utils/geo_decls.h" #include "utils/numeric.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/nabstime.h" +#include "utils/date.h" /* * Defined in adt/ @@ -204,46 +206,6 @@ extern int32 pqtest(struct varlena * vlena); /* arrayfuncs.c */ -/* date.c */ -extern RelativeTime reltimein(char *timestring); -extern char *reltimeout(RelativeTime timevalue); -extern TimeInterval tintervalin(char *intervalstr); -extern char *tintervalout(TimeInterval interval); -extern RelativeTime timespan_reltime(TimeSpan *timespan); -extern TimeSpan *reltime_timespan(RelativeTime reltime); -extern TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2); -extern AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2); -extern AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2); - -/* extern RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2); static*/ -extern int ininterval(AbsoluteTime t, TimeInterval interval); -extern RelativeTime intervalrel(TimeInterval interval); -extern AbsoluteTime timenow(void); -extern bool reltimeeq(RelativeTime t1, RelativeTime t2); -extern bool reltimene(RelativeTime t1, RelativeTime t2); -extern bool reltimelt(RelativeTime t1, RelativeTime t2); -extern bool reltimegt(RelativeTime t1, RelativeTime t2); -extern bool reltimele(RelativeTime t1, RelativeTime t2); -extern bool reltimege(RelativeTime t1, RelativeTime t2); -extern bool intervalsame(TimeInterval i1, TimeInterval i2); -extern bool intervaleq(TimeInterval i1, TimeInterval i2); -extern bool intervalne(TimeInterval i1, TimeInterval i2); -extern bool intervallt(TimeInterval i1, TimeInterval i2); -extern bool intervalgt(TimeInterval i1, TimeInterval i2); -extern bool intervalle(TimeInterval i1, TimeInterval i2); -extern bool intervalge(TimeInterval i1, TimeInterval i2); -extern bool intervalleneq(TimeInterval i, RelativeTime t); -extern bool intervallenne(TimeInterval i, RelativeTime t); -extern bool intervallenlt(TimeInterval i, RelativeTime t); -extern bool intervallengt(TimeInterval i, RelativeTime t); -extern bool intervallenle(TimeInterval i, RelativeTime t); -extern bool intervallenge(TimeInterval i, RelativeTime t); -extern bool intervalct(TimeInterval i1, TimeInterval i2); -extern bool intervalov(TimeInterval i1, TimeInterval i2); -extern AbsoluteTime intervalstart(TimeInterval i); -extern AbsoluteTime intervalend(TimeInterval i); -extern text *timeofday(void); - /* filename.c */ extern char *filename_in(char *file); extern char *filename_out(char *s); @@ -326,9 +288,6 @@ extern bool float84le(float64 arg1, float32 arg2); extern bool float84gt(float64 arg1, float32 arg2); extern bool float84ge(float64 arg1, float32 arg2); -/* geo_ops.c, geo_selfuncs.c */ -extern double *box_area(BOX *box); - /* misc.c */ extern bool nullvalue(Datum value, bool *isNull); extern bool nonnullvalue(Datum value, bool *isNull); @@ -432,19 +391,6 @@ extern ItemPointer text_tid(const text *); extern ItemPointer currtid_byreloid(Oid relOid, ItemPointer); extern ItemPointer currtid_byrelname(const text* relName, ItemPointer); -/* timestamp.c */ -extern time_t timestamp_in(const char *timestamp_str); -extern char *timestamp_out(time_t timestamp); -extern time_t now(void); -bool timestampeq(time_t t1, time_t t2); -bool timestampne(time_t t1, time_t t2); -bool timestamplt(time_t t1, time_t t2); -bool timestampgt(time_t t1, time_t t2); -bool timestample(time_t t1, time_t t2); -bool timestampge(time_t t1, time_t t2); -DateTime *timestamp_datetime(time_t timestamp); -time_t datetime_timestamp(DateTime *datetime); - /* varchar.c */ extern char *bpcharin(char *s, int dummy, int32 atttypmod); extern char *bpcharout(char *s); @@ -508,38 +454,6 @@ extern int32 byteaGetBit(struct varlena * v, int32 n); extern struct varlena *byteaSetByte(struct varlena * v, int32 n, int32 newByte); extern struct varlena *byteaSetBit(struct varlena * v, int32 n, int32 newBit); -/* datetime.c */ -extern DateADT date_in(char *datestr); -extern char *date_out(DateADT dateVal); -extern bool date_eq(DateADT dateVal1, DateADT dateVal2); -extern bool date_ne(DateADT dateVal1, DateADT dateVal2); -extern bool date_lt(DateADT dateVal1, DateADT dateVal2); -extern bool date_le(DateADT dateVal1, DateADT dateVal2); -extern bool date_gt(DateADT dateVal1, DateADT dateVal2); -extern bool date_ge(DateADT dateVal1, DateADT dateVal2); -extern int date_cmp(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_larger(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_smaller(DateADT dateVal1, DateADT dateVal2); -extern int32 date_mi(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_pli(DateADT dateVal, int32 days); -extern DateADT date_mii(DateADT dateVal, int32 days); -extern DateTime *date_datetime(DateADT date); -extern DateADT datetime_date(DateTime *datetime); -extern DateTime *datetime_datetime(DateADT date, TimeADT *time); -extern DateADT abstime_date(AbsoluteTime abstime); - -extern TimeADT *time_in(char *timestr); -extern char *time_out(TimeADT *time); -extern bool time_eq(TimeADT *time1, TimeADT *time2); -extern bool time_ne(TimeADT *time1, TimeADT *time2); -extern bool time_lt(TimeADT *time1, TimeADT *time2); -extern bool time_le(TimeADT *time1, TimeADT *time2); -extern bool time_gt(TimeADT *time1, TimeADT *time2); -extern bool time_ge(TimeADT *time1, TimeADT *time2); -extern int time_cmp(TimeADT *time1, TimeADT *time2); -extern TimeADT *datetime_time(DateTime *datetime); -extern int32 int4reltime(int32 timevalue); - /* like.c */ extern bool namelike(NameData *n, struct varlena * p); extern bool namenlike(NameData *s, struct varlena * p); diff --git a/src/include/utils/date.h b/src/include/utils/date.h new file mode 100644 index 0000000000..003ee2e026 --- /dev/null +++ b/src/include/utils/date.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * date.h + * Definitions for the SQL92 "date" and "time" types. + * + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: date.h,v 1.1 2000/02/16 17:26:26 thomas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef DATE_H +#define DATE_H + +typedef int32 DateADT; + +typedef float8 TimeADT; + +/* date.c */ +extern DateADT date_in(char *datestr); +extern char *date_out(DateADT dateVal); +extern bool date_eq(DateADT dateVal1, DateADT dateVal2); +extern bool date_ne(DateADT dateVal1, DateADT dateVal2); +extern bool date_lt(DateADT dateVal1, DateADT dateVal2); +extern bool date_le(DateADT dateVal1, DateADT dateVal2); +extern bool date_gt(DateADT dateVal1, DateADT dateVal2); +extern bool date_ge(DateADT dateVal1, DateADT dateVal2); +extern int date_cmp(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_larger(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_smaller(DateADT dateVal1, DateADT dateVal2); +extern int32 date_mi(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_pli(DateADT dateVal, int32 days); +extern DateADT date_mii(DateADT dateVal, int32 days); +extern Timestamp *date_timestamp(DateADT date); +extern DateADT timestamp_date(Timestamp *timestamp); +extern Timestamp *datetime_timestamp(DateADT date, TimeADT *time); +extern DateADT abstime_date(AbsoluteTime abstime); + +extern TimeADT *time_in(char *timestr); +extern char *time_out(TimeADT *time); +extern bool time_eq(TimeADT *time1, TimeADT *time2); +extern bool time_ne(TimeADT *time1, TimeADT *time2); +extern bool time_lt(TimeADT *time1, TimeADT *time2); +extern bool time_le(TimeADT *time1, TimeADT *time2); +extern bool time_gt(TimeADT *time1, TimeADT *time2); +extern bool time_ge(TimeADT *time1, TimeADT *time2); +extern int time_cmp(TimeADT *time1, TimeADT *time2); +extern TimeADT *timestamp_time(Timestamp *timestamp); + +#endif /* DATE_H */ diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 2a97f5e0dd..3df9ddf19f 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -1,21 +1,438 @@ /*------------------------------------------------------------------------- * * datetime.h - * Definitions for the datetime + * Definitions for the date/time and other date/time support code. + * The support code is shared with other date data types, + * including abstime, reltime, date, and time. * * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: datetime.h,v 1.9 2000/01/26 05:58:37 momjian Exp $ + * $Id: datetime.h,v 1.10 2000/02/16 17:26:26 thomas Exp $ * *------------------------------------------------------------------------- */ #ifndef DATETIME_H #define DATETIME_H -typedef int32 DateADT; +#include +#include +#include +#include "utils/timestamp.h" + +#if 0 + + +/* + * Timestamp represents absolute time. + * TimeSpan represents delta time. Keep track of months (and years) + * separately since the elapsed time spanned is unknown until instantiated + * relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + */ + +typedef double Timestamp; + +typedef struct +{ + double time; /* all time units other than months and + * years */ + int4 month; /* months and years, after time for + * alignment */ +} TimeSpan; + + +#endif + + +/* ---------------------------------------------------------------- + * time types + support macros + * + * String definitions for standard time quantities. + * + * These strings are the defaults used to form output time strings. + * Other alternate forms are hardcoded into token tables in datetime.c. + * ---------------------------------------------------------------- + */ + +#define DAGO "ago" +#define DCURRENT "current" +#define EPOCH "epoch" +#define INVALID "invalid" +#define EARLY "-infinity" +#define LATE "infinity" +#define NOW "now" +#define TODAY "today" +#define TOMORROW "tomorrow" +#define YESTERDAY "yesterday" +#define ZULU "zulu" + +#define DMICROSEC "usecond" +#define DMILLISEC "msecond" +#define DSECOND "second" +#define DMINUTE "minute" +#define DHOUR "hour" +#define DDAY "day" +#define DWEEK "week" +#define DMONTH "month" +#define DQUARTER "quarter" +#define DYEAR "year" +#define DDECADE "decade" +#define DCENTURY "century" +#define DMILLENIUM "millenium" +#define DA_D "ad" +#define DB_C "bc" +#define DTIMEZONE "timezone" + +/* + * Fundamental time field definitions for parsing. + * + * Meridian: am, pm, or 24-hour style. + * Millenium: ad, bc + */ + +#define AM 0 +#define PM 1 +#define HR24 2 + +#define AD 0 +#define BC 1 + +/* + * Fields for time decoding. + * Can't have more of these than there are bits in an unsigned int + * since these are turned into bit masks during parsing and decoding. + */ + +#define RESERV 0 +#define MONTH 1 +#define YEAR 2 +#define DAY 3 +#define TIMES 4 /* not used - thomas 1997-07-14 */ +#define TZ 5 +#define DTZ 6 +#define DTZMOD 7 +#define IGNORE 8 +#define AMPM 9 +#define HOUR 10 +#define MINUTE 11 +#define SECOND 12 +#define DOY 13 +#define DOW 14 +#define UNITS 15 +#define ADBC 16 +/* these are only for relative dates */ +#define AGO 17 +#define ABS_BEFORE 18 +#define ABS_AFTER 19 + +/* + * Token field definitions for time parsing and decoding. + * These need to fit into the datetkn table type. + * At the moment, that means keep them within [-127,127]. + * These are also used for bit masks in DecodeDateDelta() + * so actually restrict them to within [0,31] for now. + * - thomas 97/06/19 + * Not all of these fields are used for masks in DecodeDateDelta + * so allow some larger than 31. - thomas 1997-11-17 + */ + +#define DTK_NUMBER 0 +#define DTK_STRING 1 + +#define DTK_DATE 2 +#define DTK_TIME 3 +#define DTK_TZ 4 +#define DTK_AGO 5 + +#define DTK_SPECIAL 6 +#define DTK_INVALID 7 +#define DTK_CURRENT 8 +#define DTK_EARLY 9 +#define DTK_LATE 10 +#define DTK_EPOCH 11 +#define DTK_NOW 12 +#define DTK_YESTERDAY 13 +#define DTK_TODAY 14 +#define DTK_TOMORROW 15 +#define DTK_ZULU 16 + +#define DTK_DELTA 17 +#define DTK_SECOND 18 +#define DTK_MINUTE 19 +#define DTK_HOUR 20 +#define DTK_DAY 21 +#define DTK_WEEK 22 +#define DTK_MONTH 23 +#define DTK_QUARTER 24 +#define DTK_YEAR 25 +#define DTK_DECADE 26 +#define DTK_CENTURY 27 +#define DTK_MILLENIUM 28 +#define DTK_MILLISEC 29 +#define DTK_MICROSEC 30 + +#define DTK_DOW 32 +#define DTK_DOY 33 +#define DTK_TZ_HOUR 34 +#define DTK_TZ_MINUTE 35 + +/* + * Bit mask definitions for time parsing. + */ + +#define DTK_M(t) (0x01 << (t)) + +#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) +#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) + +#define MAXDATELEN 47 /* maximum possible length of an input + * date string */ +#define MAXDATEFIELDS 25 /* maximum possible number of fields in a + * date string */ +#define TOKMAXLEN 10 /* only this many chars are stored in + * datetktbl */ + +/* keep this struct small; it gets used a lot */ +typedef struct +{ +#if defined(_AIX) + char *token; +#else + char token[TOKMAXLEN]; +#endif /* _AIX */ + char type; + char value; /* this may be unsigned, alas */ +} datetkn; + + +#if 0 + + +#ifdef NAN +#define TIMESTAMP_INVALID (NAN) +#else +#define TIMESTAMP_INVALID (DBL_MIN+DBL_MIN) +#endif +#ifdef HUGE_VAL +#define TIMESTAMP_NOBEGIN (-HUGE_VAL) +#define TIMESTAMP_NOEND (HUGE_VAL) +#else +#define TIMESTAMP_NOBEGIN (-DBL_MAX) +#define TIMESTAMP_NOEND (DBL_MAX) +#endif +#define TIMESTAMP_CURRENT (DBL_MIN) +#define TIMESTAMP_EPOCH (-DBL_MIN) + +#define TIMESTAMP_INVALID(j) {j = TIMESTAMP_INVALID;} +#ifdef NAN +#define TIMESTAMP_IS_INVALID(j) (isnan(j)) +#else +#define TIMESTAMP_IS_INVALID(j) (j == TIMESTAMP_INVALID) +#endif + +#define TIMESTAMP_NOBEGIN(j) {j = DT_NOBEGIN;} +#define TIMESTAMP_IS_NOBEGIN(j) (j == TIMESTAMP_NOBEGIN) + +#define TIMESTAMP_NOEND(j) {j = TIMESTAMP_NOEND;} +#define TIMESTAMP_IS_NOEND(j) (j == TIMESTAMP_NOEND) + +#define TIMESTAMP_CURRENT(j) {j = TIMESTAMP_CURRENT;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_current(double j); + +#define TIMESTAMP_IS_CURRENT(j) timestamp_is_current(j) +#else +#define TIMESTAMP_IS_CURRENT(j) (j == TIMESTAMP_CURRENT) +#endif + +#define TIMESTAMP_EPOCH(j) {j = TIMESTAMP_EPOCH;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_epoch(double j); + +#define TIMESTAMP_IS_EPOCH(j) timestamp_is_epoch(j) +#else +#define TIMESTAMP_IS_EPOCH(j) (j == TIMESTAMP_EPOCH) +#endif + +#define TIMESTAMP_IS_RELATIVE(j) (TIMESTAMP_IS_CURRENT(j) || TIMESTAMP_IS_EPOCH(j)) +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_INVALID(j) \ + || TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) +#define TIMESTAMP_IS_RESERVED(j) (TIMESTAMP_IS_RELATIVE(j) || TIMESTAMP_NOT_FINITE(j)) + +#define TIMESPAN_INVALID(j) {(j).time = DT_INVALID;} +#ifdef NAN +#define TIMESPAN_IS_INVALID(j) (isnan((j).time)) +#else +#define TIMESPAN_IS_INVALID(j) ((j).time == DATETIME_INVALID) +#endif +#define TIMESPAN_NOT_FINITE(j) TIMESPAN_IS_INVALID(j) + +#define TIME_PREC_INV 1000000.0 +#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) + + +#endif + +/* TMODULO() + * Macro to replace modf(), which is broken on some platforms. + */ +#define TMODULO(t,q,u) \ +do { \ + q = ((t < 0)? ceil(t / u): floor(t / u)); \ + if (q != 0) \ + t -= rint(q * u); \ +} while(0) + + +/* + * Date/time validation + * Include check for leap year. + */ + +extern int day_tab[2][13]; + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* Julian date support for date2j() and j2date() + * Set the minimum year to one greater than the year of the first valid day + * to avoid having to check year and day both. - tgl 97/05/08 + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (23) + +#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ + || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ + || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#if 0 + + +/* + * datetime.c prototypes + */ + +extern DateTime *datetime_in(char *str); +extern char *datetime_out(DateTime *dt); +extern bool datetime_eq(DateTime *dt1, DateTime *dt2); +extern bool datetime_ne(DateTime *dt1, DateTime *dt2); +extern bool datetime_lt(DateTime *dt1, DateTime *dt2); +extern bool datetime_le(DateTime *dt1, DateTime *dt2); +extern bool datetime_ge(DateTime *dt1, DateTime *dt2); +extern bool datetime_gt(DateTime *dt1, DateTime *dt2); +extern bool datetime_finite(DateTime *datetime); +extern int datetime_cmp(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_smaller(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_larger(DateTime *dt1, DateTime *dt2); + +extern TimeSpan *timespan_in(char *str); +extern char *timespan_out(TimeSpan *span); +extern bool timespan_eq(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_ne(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_le(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_finite(TimeSpan *span); +extern int timespan_cmp(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_smaller(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_larger(TimeSpan *span1, TimeSpan *span2); + +extern text *datetime_text(DateTime *datetime); +extern DateTime *text_datetime(text *str); +extern text *timespan_text(TimeSpan *timespan); +extern TimeSpan *text_timespan(text *str); +extern DateTime *datetime_trunc(text *units, DateTime *datetime); +extern TimeSpan *timespan_trunc(text *units, TimeSpan *timespan); +extern float64 datetime_part(text *units, DateTime *datetime); +extern float64 timespan_part(text *units, TimeSpan *timespan); +extern text *datetime_zone(text *zone, DateTime *datetime); + +extern TimeSpan *timespan_um(TimeSpan *span); +extern TimeSpan *timespan_pl(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_mi(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_div(TimeSpan *span1, float8 *arg2); + +extern TimeSpan *datetime_mi(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_pl_span(DateTime *dt, TimeSpan *span); +extern DateTime *datetime_mi_span(DateTime *dt, TimeSpan *span); +extern TimeSpan *datetime_age(DateTime *dt1, DateTime *dt2); + + +#endif + + +extern void GetCurrentTime(struct tm * tm); +extern void j2date(int jd, int *year, int *month, int *day); +extern int date2j(int year, int month, int day); + +extern int ParseDateTime(char *timestr, char *lowstr, + char **field, int *ftype, + int maxfields, int *numfields); +extern int DecodeDateTime(char **field, int *ftype, + int nf, int *dtype, + struct tm * tm, double *fsec, int *tzp); + +extern int DecodeTimeOnly(char **field, int *ftype, int nf, + int *dtype, struct tm * tm, double *fsec); + +extern int DecodeDateDelta(char **field, int *ftype, + int nf, int *dtype, + struct tm * tm, double *fsec); + +extern int EncodeDateOnly(struct tm * tm, int style, char *str); +extern int EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str); +extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str); +extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str); + +extern int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); +extern int DecodeNumber(int flen, char *field, + int fmask, int *tmask, + struct tm * tm, double *fsec, int *is2digits); +extern int DecodeNumberField(int len, char *str, + int fmask, int *tmask, + struct tm * tm, double *fsec, int *is2digits); +extern int DecodeSpecial(int field, char *lowtoken, int *val); +extern int DecodeTime(char *str, int fmask, int *tmask, + struct tm * tm, double *fsec); +extern int DecodeTimezone(char *str, int *tzp); +extern int DecodeUnits(int field, char *lowtoken, int *val); +extern datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); + +extern int j2day(int jd); + + +#if 0 + + +static int EncodeSpecialTimestamp(Timestamp dt, char *str); +static Timestamp dt2local(Timestamp dt, int timezone); +static void dt2time(Timestamp dt, int *hour, int *min, double *sec); +static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec); +static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span); + + +#endif -typedef float8 TimeADT; #endif /* DATETIME_H */ diff --git a/src/include/utils/dt.h b/src/include/utils/dt.h deleted file mode 100644 index 739c3c22ba..0000000000 --- a/src/include/utils/dt.h +++ /dev/null @@ -1,378 +0,0 @@ -/*------------------------------------------------------------------------- - * - * dt.h - * Definitions for the date/time and other date/time support code. - * The support code is shared with other date data types, - * including abstime, reltime, date, and time. - * - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * $Id: dt.h,v 1.42 2000/01/26 05:58:37 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef DT_H -#define DT_H - -#include -#include -#include - -/* - * DateTime represents absolute time. - * TimeSpan represents delta time. Keep track of months (and years) - * separately since the elapsed time spanned is unknown until instantiated - * relative to an absolute time. - * - * Note that Postgres uses "time interval" to mean a bounded interval, - * consisting of a beginning and ending time, not a time span - thomas 97/03/20 - */ - -typedef double DateTime; - -typedef struct -{ - double time; /* all time units other than months and - * years */ - int4 month; /* months and years, after time for - * alignment */ -} TimeSpan; - - -/* ---------------------------------------------------------------- - * time types + support macros - * - * String definitions for standard time quantities. - * - * These strings are the defaults used to form output time strings. - * Other alternate forms are hardcoded into token tables in dt.c. - * ---------------------------------------------------------------- - */ - -#define DAGO "ago" -#define DCURRENT "current" -#define EPOCH "epoch" -#define INVALID "invalid" -#define EARLY "-infinity" -#define LATE "infinity" -#define NOW "now" -#define TODAY "today" -#define TOMORROW "tomorrow" -#define YESTERDAY "yesterday" -#define ZULU "zulu" - -#define DMICROSEC "usecond" -#define DMILLISEC "msecond" -#define DSECOND "second" -#define DMINUTE "minute" -#define DHOUR "hour" -#define DDAY "day" -#define DWEEK "week" -#define DMONTH "month" -#define DQUARTER "quarter" -#define DYEAR "year" -#define DDECADE "decade" -#define DCENTURY "century" -#define DMILLENIUM "millenium" -#define DA_D "ad" -#define DB_C "bc" -#define DTIMEZONE "timezone" - -/* - * Fundamental time field definitions for parsing. - * - * Meridian: am, pm, or 24-hour style. - * Millenium: ad, bc - */ - -#define AM 0 -#define PM 1 -#define HR24 2 - -#define AD 0 -#define BC 1 - -/* - * Fields for time decoding. - * Can't have more of these than there are bits in an unsigned int - * since these are turned into bit masks during parsing and decoding. - */ - -#define RESERV 0 -#define MONTH 1 -#define YEAR 2 -#define DAY 3 -#define TIMES 4 /* not used - thomas 1997-07-14 */ -#define TZ 5 -#define DTZ 6 -#define DTZMOD 7 -#define IGNORE 8 -#define AMPM 9 -#define HOUR 10 -#define MINUTE 11 -#define SECOND 12 -#define DOY 13 -#define DOW 14 -#define UNITS 15 -#define ADBC 16 -/* these are only for relative dates */ -#define AGO 17 -#define ABS_BEFORE 18 -#define ABS_AFTER 19 - -/* - * Token field definitions for time parsing and decoding. - * These need to fit into the datetkn table type. - * At the moment, that means keep them within [-127,127]. - * These are also used for bit masks in DecodeDateDelta() - * so actually restrict them to within [0,31] for now. - * - thomas 97/06/19 - * Not all of these fields are used for masks in DecodeDateDelta - * so allow some larger than 31. - thomas 1997-11-17 - */ - -#define DTK_NUMBER 0 -#define DTK_STRING 1 - -#define DTK_DATE 2 -#define DTK_TIME 3 -#define DTK_TZ 4 -#define DTK_AGO 5 - -#define DTK_SPECIAL 6 -#define DTK_INVALID 7 -#define DTK_CURRENT 8 -#define DTK_EARLY 9 -#define DTK_LATE 10 -#define DTK_EPOCH 11 -#define DTK_NOW 12 -#define DTK_YESTERDAY 13 -#define DTK_TODAY 14 -#define DTK_TOMORROW 15 -#define DTK_ZULU 16 - -#define DTK_DELTA 17 -#define DTK_SECOND 18 -#define DTK_MINUTE 19 -#define DTK_HOUR 20 -#define DTK_DAY 21 -#define DTK_WEEK 22 -#define DTK_MONTH 23 -#define DTK_QUARTER 24 -#define DTK_YEAR 25 -#define DTK_DECADE 26 -#define DTK_CENTURY 27 -#define DTK_MILLENIUM 28 -#define DTK_MILLISEC 29 -#define DTK_MICROSEC 30 - -#define DTK_DOW 32 -#define DTK_DOY 33 -#define DTK_TZ_HOUR 34 -#define DTK_TZ_MINUTE 35 - -/* - * Bit mask definitions for time parsing. - */ - -#define DTK_M(t) (0x01 << (t)) - -#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) -#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) - -#define MAXDATELEN 47 /* maximum possible length of an input - * date string */ -#define MAXDATEFIELDS 25 /* maximum possible number of fields in a - * date string */ -#define TOKMAXLEN 10 /* only this many chars are stored in - * datetktbl */ - -/* keep this struct small; it gets used a lot */ -typedef struct -{ -#if defined(_AIX) - char *token; -#else - char token[TOKMAXLEN]; -#endif /* _AIX */ - char type; - char value; /* this may be unsigned, alas */ -} datetkn; - -#ifdef NAN -#define DT_INVALID (NAN) -#else -#define DT_INVALID (DBL_MIN+DBL_MIN) -#endif -#ifdef HUGE_VAL -#define DT_NOBEGIN (-HUGE_VAL) -#define DT_NOEND (HUGE_VAL) -#else -#define DT_NOBEGIN (-DBL_MAX) -#define DT_NOEND (DBL_MAX) -#endif -#define DT_CURRENT (DBL_MIN) -#define DT_EPOCH (-DBL_MIN) - -#define DATETIME_INVALID(j) {j = DT_INVALID;} -#ifdef NAN -#define DATETIME_IS_INVALID(j) (isnan(j)) -#else -#define DATETIME_IS_INVALID(j) (j == DT_INVALID) -#endif - -#define DATETIME_NOBEGIN(j) {j = DT_NOBEGIN;} -#define DATETIME_IS_NOBEGIN(j) (j == DT_NOBEGIN) - -#define DATETIME_NOEND(j) {j = DT_NOEND;} -#define DATETIME_IS_NOEND(j) (j == DT_NOEND) - -#define DATETIME_CURRENT(j) {j = DT_CURRENT;} -#if defined(linux) && defined(__powerpc__) -extern int datetime_is_current(double j); - -#define DATETIME_IS_CURRENT(j) datetime_is_current(j) -#else -#define DATETIME_IS_CURRENT(j) (j == DT_CURRENT) -#endif - -#define DATETIME_EPOCH(j) {j = DT_EPOCH;} -#if defined(linux) && defined(__powerpc__) -extern int datetime_is_epoch(double j); - -#define DATETIME_IS_EPOCH(j) datetime_is_epoch(j) -#else -#define DATETIME_IS_EPOCH(j) (j == DT_EPOCH) -#endif - -#define DATETIME_IS_RELATIVE(j) (DATETIME_IS_CURRENT(j) || DATETIME_IS_EPOCH(j)) -#define DATETIME_NOT_FINITE(j) (DATETIME_IS_INVALID(j) \ - || DATETIME_IS_NOBEGIN(j) || DATETIME_IS_NOEND(j)) -#define DATETIME_IS_RESERVED(j) (DATETIME_IS_RELATIVE(j) || DATETIME_NOT_FINITE(j)) - -#define TIMESPAN_INVALID(j) {(j).time = DT_INVALID;} -#ifdef NAN -#define TIMESPAN_IS_INVALID(j) (isnan((j).time)) -#else -#define TIMESPAN_IS_INVALID(j) ((j).time == DT_INVALID) -#endif -#define TIMESPAN_NOT_FINITE(j) TIMESPAN_IS_INVALID(j) - -#define TIME_PREC_INV 1000000.0 -#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) - - - -/* - * Date/time validation - * Include check for leap year. - */ - -extern int day_tab[2][13]; - -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - -/* Julian date support for date2j() and j2date() - * Set the minimum year to one greater than the year of the first valid day - * to avoid having to check year and day both. - tgl 97/05/08 - */ - -#define JULIAN_MINYEAR (-4713) -#define JULIAN_MINMONTH (11) -#define JULIAN_MINDAY (23) - -#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ - || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ - || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) - -#define UTIME_MINYEAR (1901) -#define UTIME_MINMONTH (12) -#define UTIME_MINDAY (14) -#define UTIME_MAXYEAR (2038) -#define UTIME_MAXMONTH (01) -#define UTIME_MAXDAY (18) - -#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ - || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ - || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ - && ((y < UTIME_MAXYEAR) \ - || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ - || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) - -/* - * dt.c prototypes - */ - -extern DateTime *datetime_in(char *str); -extern char *datetime_out(DateTime *dt); -extern bool datetime_eq(DateTime *dt1, DateTime *dt2); -extern bool datetime_ne(DateTime *dt1, DateTime *dt2); -extern bool datetime_lt(DateTime *dt1, DateTime *dt2); -extern bool datetime_le(DateTime *dt1, DateTime *dt2); -extern bool datetime_ge(DateTime *dt1, DateTime *dt2); -extern bool datetime_gt(DateTime *dt1, DateTime *dt2); -extern bool datetime_finite(DateTime *datetime); -extern int datetime_cmp(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_smaller(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_larger(DateTime *dt1, DateTime *dt2); - -extern TimeSpan *timespan_in(char *str); -extern char *timespan_out(TimeSpan *span); -extern bool timespan_eq(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_ne(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_le(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_finite(TimeSpan *span); -extern int timespan_cmp(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_smaller(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_larger(TimeSpan *span1, TimeSpan *span2); - -extern text *datetime_text(DateTime *datetime); -extern DateTime *text_datetime(text *str); -extern text *timespan_text(TimeSpan *timespan); -extern TimeSpan *text_timespan(text *str); -extern DateTime *datetime_trunc(text *units, DateTime *datetime); -extern TimeSpan *timespan_trunc(text *units, TimeSpan *timespan); -extern float64 datetime_part(text *units, DateTime *datetime); -extern float64 timespan_part(text *units, TimeSpan *timespan); -extern text *datetime_zone(text *zone, DateTime *datetime); - -extern TimeSpan *timespan_um(TimeSpan *span); -extern TimeSpan *timespan_pl(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_mi(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_div(TimeSpan *span1, float8 *arg2); - -extern TimeSpan *datetime_mi(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_pl_span(DateTime *dt, TimeSpan *span); -extern DateTime *datetime_mi_span(DateTime *dt, TimeSpan *span); -extern TimeSpan *datetime_age(DateTime *dt1, DateTime *dt2); - -extern void GetCurrentTime(struct tm * tm); -extern DateTime SetDateTime(DateTime datetime); -extern int tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime *dt); -extern int datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn); - -extern void j2date(int jd, int *year, int *month, int *day); -extern int date2j(int year, int month, int day); - -extern int ParseDateTime(char *timestr, char *lowstr, - char **field, int *ftype, int maxfields, int *numfields); -extern int DecodeDateTime(char **field, int *ftype, - int nf, int *dtype, struct tm * tm, double *fsec, int *tzp); - -extern int DecodeTimeOnly(char **field, int *ftype, int nf, - int *dtype, struct tm * tm, double *fsec); - -extern int DecodeDateDelta(char **field, int *ftype, - int nf, int *dtype, struct tm * tm, double *fsec); - -extern int EncodeDateOnly(struct tm * tm, int style, char *str); -extern int EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str); -extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str); -extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str); - -#endif /* DT_H */ diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index 51c649fd9d..39259afff2 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -2,7 +2,7 @@ /* ----------------------------------------------------------------------- * formatting.h * - * $Id: formatting.h,v 1.2 2000/02/08 15:56:57 momjian Exp $ + * $Id: formatting.h,v 1.3 2000/02/16 17:26:26 thomas Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc @@ -18,16 +18,14 @@ #ifndef _FORMATTING_H_ #define _FORMATTING_H_ -extern text *datetime_to_char(DateTime *dt, text *fmt); -extern text *timestamp_to_char(time_t dt, text *fmt); -extern DateTime *to_datetime(text *date_str, text *fmt); -extern time_t to_timestamp(text *date_str, text *fmt); -extern DateADT to_date(text *date_str, text *fmt); -extern Numeric numeric_to_number(text *value, text *fmt); -extern text *numeric_to_char(Numeric value, text *fmt); -extern text *int4_to_char(int32 value, text *fmt); -extern text *int8_to_char(int64 *value, text *fmt); -extern text *float4_to_char(float32 value, text *fmt); -extern text *float8_to_char(float64 value, text *fmt); +extern text *timestamp_to_char(Timestamp *dt, text *fmt); +extern Timestamp *to_timestamp(text *date_str, text *fmt); +extern DateADT to_date(text *date_str, text *fmt); +extern Numeric numeric_to_number(text *value, text *fmt); +extern text *numeric_to_char(Numeric value, text *fmt); +extern text *int4_to_char(int32 value, text *fmt); +extern text *int8_to_char(int64 *value, text *fmt); +extern text *float4_to_char(float32 value, text *fmt); +extern text *float8_to_char(float64 value, text *fmt); #endif diff --git a/src/include/utils/nabstime.h b/src/include/utils/nabstime.h index 4da1c28343..09eea75ec6 100644 --- a/src/include/utils/nabstime.h +++ b/src/include/utils/nabstime.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nabstime.h,v 1.22 2000/01/26 05:58:38 momjian Exp $ + * $Id: nabstime.h,v 1.23 2000/02/16 17:26:26 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,8 @@ #define NABSTIME_H #include -#include "utils/dt.h" +#include "utils/timestamp.h" +#include "utils/datetime.h" /* ---------------------------------------------------------------- @@ -119,11 +120,51 @@ extern bool abstimele(AbsoluteTime t1, AbsoluteTime t2); extern bool abstimege(AbsoluteTime t1, AbsoluteTime t2); extern bool abstime_finite(AbsoluteTime time); -extern AbsoluteTime datetime_abstime(DateTime *datetime); -extern DateTime *abstime_datetime(AbsoluteTime abstime); +extern AbsoluteTime timestamp_abstime(Timestamp *timestamp); +extern Timestamp *abstime_timestamp(AbsoluteTime abstime); extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2); extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn); +extern RelativeTime reltimein(char *timestring); +extern char *reltimeout(RelativeTime timevalue); +extern TimeInterval tintervalin(char *intervalstr); +extern char *tintervalout(TimeInterval interval); +extern RelativeTime interval_reltime(Interval *interval); +extern Interval *reltime_interval(RelativeTime reltime); +extern TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2); +extern AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2); +extern AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2); + +/* extern RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2); static*/ +extern int intinterval(AbsoluteTime t, TimeInterval interval); +extern RelativeTime tintervalrel(TimeInterval interval); +extern AbsoluteTime timenow(void); +extern bool reltimeeq(RelativeTime t1, RelativeTime t2); +extern bool reltimene(RelativeTime t1, RelativeTime t2); +extern bool reltimelt(RelativeTime t1, RelativeTime t2); +extern bool reltimegt(RelativeTime t1, RelativeTime t2); +extern bool reltimele(RelativeTime t1, RelativeTime t2); +extern bool reltimege(RelativeTime t1, RelativeTime t2); +extern bool tintervalsame(TimeInterval i1, TimeInterval i2); +extern bool tintervaleq(TimeInterval i1, TimeInterval i2); +extern bool tintervalne(TimeInterval i1, TimeInterval i2); +extern bool tintervallt(TimeInterval i1, TimeInterval i2); +extern bool tintervalgt(TimeInterval i1, TimeInterval i2); +extern bool tintervalle(TimeInterval i1, TimeInterval i2); +extern bool tintervalge(TimeInterval i1, TimeInterval i2); +extern bool tintervalleneq(TimeInterval i, RelativeTime t); +extern bool tintervallenne(TimeInterval i, RelativeTime t); +extern bool tintervallenlt(TimeInterval i, RelativeTime t); +extern bool tintervallengt(TimeInterval i, RelativeTime t); +extern bool tintervallenle(TimeInterval i, RelativeTime t); +extern bool tintervallenge(TimeInterval i, RelativeTime t); +extern bool tintervalct(TimeInterval i1, TimeInterval i2); +extern bool tintervalov(TimeInterval i1, TimeInterval i2); +extern AbsoluteTime tintervalstart(TimeInterval i); +extern AbsoluteTime tintervalend(TimeInterval i); +extern int32 int4reltime(int32 timevalue); +extern text *timeofday(void); + #endif /* NABSTIME_H */ diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h new file mode 100644 index 0000000000..27a5288cf3 --- /dev/null +++ b/src/include/utils/timestamp.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Definitions for the SQL92 "timestamp" and "interval" types. + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: timestamp.h,v 1.1 2000/02/16 17:26:26 thomas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef TIMESTAMP_H +#define TIMESTAMP_H + +#include +#include +#include + +/* + * Timestamp represents absolute time. + * Interval represents delta time. Keep track of months (and years) + * separately since the elapsed time spanned is unknown until instantiated + * relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + */ + +typedef double Timestamp; + +typedef struct +{ + double time; /* all time units other than months and + * years */ + int4 month; /* months and years, after time for + * alignment */ +} Interval; + + +#ifdef NAN +#define DT_INVALID (NAN) +#else +#define DT_INVALID (DBL_MIN+DBL_MIN) +#endif +#ifdef HUGE_VAL +#define DT_NOBEGIN (-HUGE_VAL) +#define DT_NOEND (HUGE_VAL) +#else +#define DT_NOBEGIN (-DBL_MAX) +#define DT_NOEND (DBL_MAX) +#endif +#define DT_CURRENT (DBL_MIN) +#define DT_EPOCH (-DBL_MIN) + +#define TIMESTAMP_INVALID(j) {j = DT_INVALID;} +#ifdef NAN +#define TIMESTAMP_IS_INVALID(j) (isnan(j)) +#else +#define TIMESTAMP_IS_INVALID(j) (j == DT_INVALID) +#endif + +#define TIMESTAMP_NOBEGIN(j) {j = DT_NOBEGIN;} +#define TIMESTAMP_IS_NOBEGIN(j) (j == DT_NOBEGIN) + +#define TIMESTAMP_NOEND(j) {j = DT_NOEND;} +#define TIMESTAMP_IS_NOEND(j) (j == DT_NOEND) + +#define TIMESTAMP_CURRENT(j) {j = DT_CURRENT;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_current(double j); + +#define TIMESTAMP_IS_CURRENT(j) timestamp_is_current(j) +#else +#define TIMESTAMP_IS_CURRENT(j) (j == DT_CURRENT) +#endif + +#define TIMESTAMP_EPOCH(j) {j = DT_EPOCH;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_epoch(double j); + +#define TIMESTAMP_IS_EPOCH(j) timestamp_is_epoch(j) +#else +#define TIMESTAMP_IS_EPOCH(j) (j == DT_EPOCH) +#endif + +#define TIMESTAMP_IS_RELATIVE(j) (TIMESTAMP_IS_CURRENT(j) || TIMESTAMP_IS_EPOCH(j)) +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_INVALID(j) \ + || TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) +#define TIMESTAMP_IS_RESERVED(j) (TIMESTAMP_IS_RELATIVE(j) || TIMESTAMP_NOT_FINITE(j)) + +#define INTERVAL_INVALID(j) {(j).time = DT_INVALID;} +#ifdef NAN +#define INTERVAL_IS_INVALID(j) (isnan((j).time)) +#else +#define INTERVAL_IS_INVALID(j) ((j).time == DT_INVALID) +#endif +#define INTERVAL_NOT_FINITE(j) INTERVAL_IS_INVALID(j) + +#define TIME_PREC_INV 1000000.0 +#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) + + +#if 0 + + +/* + * Date/time validation + * Include check for leap year. + */ + +extern int day_tab[2][13]; + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* Julian date support for date2j() and j2date() + * Set the minimum year to one greater than the year of the first valid day + * to avoid having to check year and day both. - tgl 97/05/08 + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (23) + +#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ + || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ + || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#endif + + +/* + * timestamp.c prototypes + */ + +extern Timestamp *timestamp_in(char *str); +extern char *timestamp_out(Timestamp *dt); +extern bool timestamp_eq(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_ne(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_lt(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_le(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_ge(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_gt(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_finite(Timestamp *timestamp); +extern int timestamp_cmp(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_smaller(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_larger(Timestamp *dt1, Timestamp *dt2); + +extern Interval *interval_in(char *str); +extern char *interval_out(Interval *span); +extern bool interval_eq(Interval *span1, Interval *span2); +extern bool interval_ne(Interval *span1, Interval *span2); +extern bool interval_lt(Interval *span1, Interval *span2); +extern bool interval_le(Interval *span1, Interval *span2); +extern bool interval_ge(Interval *span1, Interval *span2); +extern bool interval_gt(Interval *span1, Interval *span2); +extern bool interval_finite(Interval *span); +extern int interval_cmp(Interval *span1, Interval *span2); +extern Interval *interval_smaller(Interval *span1, Interval *span2); +extern Interval *interval_larger(Interval *span1, Interval *span2); + +extern text *timestamp_text(Timestamp *timestamp); +extern Timestamp *text_timestamp(text *str); +extern text *interval_text(Interval *interval); +extern Interval *text_interval(text *str); +extern Timestamp *timestamp_trunc(text *units, Timestamp *timestamp); +extern Interval *interval_trunc(text *units, Interval *interval); +extern float64 timestamp_part(text *units, Timestamp *timestamp); +extern float64 interval_part(text *units, Interval *interval); +extern text *timestamp_zone(text *zone, Timestamp *timestamp); + +extern Interval *interval_um(Interval *span); +extern Interval *interval_pl(Interval *span1, Interval *span2); +extern Interval *interval_mi(Interval *span1, Interval *span2); +extern Interval *interval_div(Interval *span1, float8 *arg2); + +extern Interval *timestamp_mi(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_pl_span(Timestamp *dt, Interval *span); +extern Timestamp *timestamp_mi_span(Timestamp *dt, Interval *span); +extern Interval *timestamp_age(Timestamp *dt1, Timestamp *dt2); + +extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt); +extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn); + +extern Timestamp SetTimestamp(Timestamp timestamp); +extern Timestamp dt2local(Timestamp dt, int timezone); +extern void dt2time(Timestamp dt, int *hour, int *min, double *sec); +extern int EncodeSpecialTimestamp(Timestamp dt, char *str); +extern int interval2tm(Interval span, struct tm * tm, float8 *fsec); +extern int tm2interval(struct tm * tm, double fsec, Interval *span); +extern Timestamp *now(void); + +#endif /* TIMESTAMP_H */