*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.142 2008/07/07 18:09:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.143 2008/10/14 17:12:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#endif
+static void EncodeSpecialDate(DateADT dt, char *str);
static int time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
static int timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
GetEpochTime(tm);
break;
+ case DTK_LATE:
+ DATE_NOEND(date);
+ PG_RETURN_DATEADT(date);
+
+ case DTK_EARLY:
+ DATE_NOBEGIN(date);
+ PG_RETURN_DATEADT(date);
+
default:
DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
break;
*tm = &tt;
char buf[MAXDATELEN + 1];
- j2date(date + POSTGRES_EPOCH_JDATE,
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
-
- EncodeDateOnly(tm, DateStyle, buf);
+ if (DATE_NOT_FINITE(date))
+ EncodeSpecialDate(date, buf);
+ else
+ {
+ j2date(date + POSTGRES_EPOCH_JDATE,
+ &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ EncodeDateOnly(tm, DateStyle, buf);
+ }
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
+/*
+ * Convert reserved date values to string.
+ */
+static void
+EncodeSpecialDate(DateADT dt, char *str)
+{
+ if (DATE_IS_NOBEGIN(dt))
+ strcpy(str, EARLY);
+ else if (DATE_IS_NOEND(dt))
+ strcpy(str, LATE);
+ else /* shouldn't happen */
+ elog(ERROR, "invalid argument for EncodeSpecialDate");
+}
+
/*
* Comparison functions for dates
PG_RETURN_INT32(0);
}
+Datum
+date_finite(PG_FUNCTION_ARGS)
+{
+ DateADT date = PG_GETARG_DATEADT(0);
+
+ PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
+}
+
Datum
date_larger(PG_FUNCTION_ARGS)
{
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
+ if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("cannot subtract infinite dates")));
+
PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
}
DateADT dateVal = PG_GETARG_DATEADT(0);
int32 days = PG_GETARG_INT32(1);
+ if (DATE_NOT_FINITE(dateVal))
+ days = 0; /* can't change infinity */
+
PG_RETURN_DATEADT(dateVal + days);
}
DateADT dateVal = PG_GETARG_DATEADT(0);
int32 days = PG_GETARG_INT32(1);
+ if (DATE_NOT_FINITE(dateVal))
+ days = 0; /* can't change infinity */
+
PG_RETURN_DATEADT(dateVal - days);
}
{
Timestamp result;
+ if (DATE_IS_NOBEGIN(dateVal))
+ TIMESTAMP_NOBEGIN(result);
+ else if (DATE_IS_NOEND(dateVal))
+ TIMESTAMP_NOEND(result);
+ else
+ {
#ifdef HAVE_INT64_TIMESTAMP
- /* date is days since 2000, timestamp is microseconds since same... */
- result = dateVal * USECS_PER_DAY;
- /* Date's range is wider than timestamp's, so must check for overflow */
- if (result / USECS_PER_DAY != dateVal)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("date out of range for timestamp")));
+ /* date is days since 2000, timestamp is microseconds since same... */
+ result = dateVal * USECS_PER_DAY;
+ /* Date's range is wider than timestamp's, so check for overflow */
+ if (result / USECS_PER_DAY != dateVal)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("date out of range for timestamp")));
#else
- /* date is days since 2000, timestamp is seconds since same... */
- result = dateVal * (double) SECS_PER_DAY;
+ /* date is days since 2000, timestamp is seconds since same... */
+ result = dateVal * (double) SECS_PER_DAY;
#endif
+ }
return result;
}
*tm = &tt;
int tz;
- j2date(dateVal + POSTGRES_EPOCH_JDATE,
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
-
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- tz = DetermineTimeZoneOffset(tm, session_timezone);
+ if (DATE_IS_NOBEGIN(dateVal))
+ TIMESTAMP_NOBEGIN(result);
+ else if (DATE_IS_NOEND(dateVal))
+ TIMESTAMP_NOEND(result);
+ else
+ {
+ j2date(dateVal + POSTGRES_EPOCH_JDATE,
+ &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ tz = DetermineTimeZoneOffset(tm, session_timezone);
#ifdef HAVE_INT64_TIMESTAMP
- result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
- /* Date's range is wider than timestamp's, so must check for overflow */
- if ((result - tz * USECS_PER_SEC) / USECS_PER_DAY != dateVal)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("date out of range for timestamp")));
+ result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
+ /* Date's range is wider than timestamp's, so check for overflow */
+ if ((result - tz * USECS_PER_SEC) / USECS_PER_DAY != dateVal)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("date out of range for timestamp")));
#else
- result = dateVal * (double) SECS_PER_DAY + tz;
+ result = dateVal * (double) SECS_PER_DAY + tz;
#endif
+ }
return result;
}
*tm = &tt;
fsec_t fsec;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
-
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("timestamp out of range")));
+ if (TIMESTAMP_IS_NOBEGIN(timestamp))
+ DATE_NOBEGIN(result);
+ else if (TIMESTAMP_IS_NOEND(timestamp))
+ DATE_NOEND(result);
+ else
+ {
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
- result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+ result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+ }
PG_RETURN_DATEADT(result);
}
int tz;
char *tzn;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_NULL();
-
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("timestamp out of range")));
+ if (TIMESTAMP_IS_NOBEGIN(timestamp))
+ DATE_NOBEGIN(result);
+ else if (TIMESTAMP_IS_NOEND(timestamp))
+ DATE_NOEND(result);
+ else
+ {
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
- result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+ result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+ }
PG_RETURN_DATEADT(result);
}
switch (abstime)
{
case INVALID_ABSTIME:
- case NOSTART_ABSTIME:
- case NOEND_ABSTIME:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert reserved abstime value to date")));
+ result = 0; /* keep compiler quiet */
+ break;
- /*
- * pretend to drop through to make compiler think that result will
- * be set
- */
+ case NOSTART_ABSTIME:
+ DATE_NOBEGIN(result);
+ break;
+
+ case NOEND_ABSTIME:
+ DATE_NOEND(result);
+ break;
default:
abstime2tm(abstime, &tz, tm, NULL);
TimeADT time = PG_GETARG_TIMEADT(1);
Timestamp result;
- result = DatumGetTimestamp(DirectFunctionCall1(date_timestamp,
- DateADTGetDatum(date)));
- result += time;
+ result = date2timestamp(date);
+ if (!TIMESTAMP_NOT_FINITE(result))
+ result += time;
PG_RETURN_TIMESTAMP(result);
}
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
TimestampTz result;
+ if (DATE_IS_NOBEGIN(date))
+ TIMESTAMP_NOBEGIN(result);
+ else if (DATE_IS_NOEND(date))
+ TIMESTAMP_NOEND(result);
+ else
+ {
#ifdef HAVE_INT64_TIMESTAMP
- result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
+ result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
#else
- result = date * (double) SECS_PER_DAY + time->time + time->zone;
+ result = date * (double) SECS_PER_DAY + time->time + time->zone;
#endif
+ }
PG_RETURN_TIMESTAMP(result);
}