aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/date.c485
-rw-r--r--src/backend/utils/adt/timestamp.c20
2 files changed, 427 insertions, 78 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 8afe5450d27..9346f2ab68c 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.94 2003/11/29 19:51:58 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.95 2004/02/14 20:16:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -150,6 +150,10 @@ date_send(PG_FUNCTION_ARGS)
}
+/*
+ * Comparison functions for dates
+ */
+
Datum
date_eq(PG_FUNCTION_ARGS)
{
@@ -269,61 +273,441 @@ date_mii(PG_FUNCTION_ARGS)
PG_RETURN_DATEADT(dateVal - days);
}
-#if NOT_USED
-/* date_pl_interval() and date_mi_interval() are probably
- * better implmented by converting the input date
- * to timestamp without time zone. So that is what we do
- * in pg_proc.h - thomas 2002-03-11
+/*
+ * Internal routines for promoting date to timestamp and timestamp with
+ * time zone
*/
+#ifdef HAVE_INT64_TIMESTAMP
+/* date is days since 2000, timestamp is microseconds since same... */
+#define date2timestamp(dateVal) \
+ ((Timestamp) ((dateVal) * INT64CONST(86400000000)))
+#else
+/* date is days since 2000, timestamp is seconds since same... */
+#define date2timestamp(dateVal) \
+ ((Timestamp) ((dateVal) * 86400.0))
+#endif
+
+static TimestampTz
+date2timestamptz(DateADT dateVal)
+{
+ TimestampTz result;
+ struct tm tt,
+ *tm = &tt;
+
+ j2date(dateVal + POSTGRES_EPOCH_JDATE,
+ &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+
+ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ {
+ int tz;
+
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ tz = DetermineLocalTimeZone(tm);
+
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (dateVal * INT64CONST(86400000000))
+ + (tz * INT64CONST(1000000));
+#else
+ result = dateVal * 86400.0 + tz;
+#endif
+ }
+ else
+ {
+ /* Outside of range for timezone support, so assume UTC */
+#ifdef HAVE_INT64_TIMESTAMP
+ result = (dateVal * INT64CONST(86400000000));
+#else
+ result = dateVal * 86400.0;
+#endif
+ }
+
+ return result;
+}
+
+
+/*
+ * Crosstype comparison functions for dates
+ */
+
+Datum
+date_eq_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
+}
+
+Datum
+date_ne_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
+}
+
+Datum
+date_lt_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
+}
+
+Datum
+date_gt_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
+}
+
+Datum
+date_le_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
+}
+
+Datum
+date_ge_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
+}
+
+Datum
+date_cmp_timestamp(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
+ Timestamp dt1;
+
+ dt1 = date2timestamp(dateVal);
+
+ PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
+}
+
+Datum
+date_eq_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
+}
+
+Datum
+date_ne_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
+}
+
+Datum
+date_lt_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
+}
+
+Datum
+date_gt_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
+}
+
+Datum
+date_le_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
+}
+
+Datum
+date_ge_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
+}
+
+Datum
+date_cmp_timestamptz(PG_FUNCTION_ARGS)
+{
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+ TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
+ TimestampTz dt1;
+
+ dt1 = date2timestamptz(dateVal);
+
+ PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
+}
+
+Datum
+timestamp_eq_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
+}
+
+Datum
+timestamp_ne_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
+}
+
+Datum
+timestamp_lt_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
+}
+
+Datum
+timestamp_gt_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
+}
+
+Datum
+timestamp_le_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
+}
+
+Datum
+timestamp_ge_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
+}
+
+Datum
+timestamp_cmp_date(PG_FUNCTION_ARGS)
+{
+ Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ Timestamp dt2;
+
+ dt2 = date2timestamp(dateVal);
+
+ PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
+}
+
+Datum
+timestamptz_eq_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
+}
+
+Datum
+timestamptz_ne_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
+}
+
+Datum
+timestamptz_lt_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
+}
+
+Datum
+timestamptz_gt_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
+}
+
+Datum
+timestamptz_le_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
+}
+
+Datum
+timestamptz_ge_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
+}
+
+Datum
+timestamptz_cmp_date(PG_FUNCTION_ARGS)
+{
+ TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
+ DateADT dateVal = PG_GETARG_DATEADT(1);
+ TimestampTz dt2;
+
+ dt2 = date2timestamptz(dateVal);
+
+ PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
+}
+
+
/* Add an interval to a date, giving a new date.
* Must handle both positive and negative intervals.
+ *
+ * We implement this by promoting the date to timestamp (without time zone)
+ * and then using the timestamp plus interval function.
*/
Datum
date_pl_interval(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
- struct tm tt,
- *tm = &tt;
+ Timestamp dateStamp;
- if (span->month != 0)
- {
- j2date(dateVal + POSTGRES_EPOCH_JDATE,
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
- tm->tm_mon += span->month;
- dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
- }
- if (span->time != 0)
- dateVal += (span->time / 86400e0);
+ dateStamp = date2timestamp(dateVal);
- PG_RETURN_DATEADT(dateVal);
+ return DirectFunctionCall2(timestamp_pl_interval,
+ TimestampGetDatum(dateStamp),
+ PointerGetDatum(span));
}
/* Subtract an interval from a date, giving a new date.
* Must handle both positive and negative intervals.
+ *
+ * We implement this by promoting the date to timestamp (without time zone)
+ * and then using the timestamp minus interval function.
*/
Datum
date_mi_interval(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
- struct tm tt,
- *tm = &tt;
+ Timestamp dateStamp;
- if (span->month != 0)
- {
- j2date(dateVal + POSTGRES_EPOCH_JDATE,
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
- tm->tm_mon -= span->month;
- dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
- }
- if (span->time != 0)
- dateVal -= (span->time / 86400e0);
+ dateStamp = date2timestamp(dateVal);
- PG_RETURN_DATEADT(dateVal);
+ return DirectFunctionCall2(timestamp_mi_interval,
+ TimestampGetDatum(dateStamp),
+ PointerGetDatum(span));
}
-#endif
/* date_timestamp()
* Convert date to timestamp data type.
@@ -334,13 +718,7 @@ date_timestamp(PG_FUNCTION_ARGS)
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp result;
-#ifdef HAVE_INT64_TIMESTAMP
- /* date is days since 2000, timestamp is microseconds since same... */
- result = dateVal * INT64CONST(86400000000);
-#else
- /* date is days since 2000, timestamp is seconds since same... */
- result = dateVal * 86400.0;
-#endif
+ result = date2timestamp(dateVal);
PG_RETURN_TIMESTAMP(result);
}
@@ -380,37 +758,8 @@ date_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz result;
- struct tm tt,
- *tm = &tt;
-
- j2date(dateVal + POSTGRES_EPOCH_JDATE,
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
-
- if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
- {
- int tz;
-
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- tz = DetermineLocalTimeZone(tm);
-#ifdef HAVE_INT64_TIMESTAMP
- result = (dateVal * INT64CONST(86400000000))
- + (tz * INT64CONST(1000000));
-#else
- result = dateVal * 86400.0 + tz;
-#endif
- }
- else
- {
- /* Outside of range for timezone support, so assume UTC */
-#ifdef HAVE_INT64_TIMESTAMP
- result = (dateVal * INT64CONST(86400000000));
-#else
- result = dateVal * 86400.0;
-#endif
- }
+ result = date2timestamptz(dateVal);
PG_RETURN_TIMESTAMP(result);
}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 7aab2455a26..ad79025ebc0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.98 2003/12/25 03:36:23 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.99 2004/02/14 20:16:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1296,7 +1296,7 @@ SetEpochTimestamp(void)
*
* collate invalid timestamp at the end
*/
-static int
+int
timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
{
#ifdef HAVE_INT64_TIMESTAMP
@@ -1703,7 +1703,7 @@ timestamp_mi(PG_FUNCTION_ARGS)
}
-/* timestamp_pl_span()
+/* timestamp_pl_interval()
* 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.
@@ -1713,7 +1713,7 @@ timestamp_mi(PG_FUNCTION_ARGS)
* Lastly, add in the "quantitative time".
*/
Datum
-timestamp_pl_span(PG_FUNCTION_ARGS)
+timestamp_pl_interval(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
@@ -1764,7 +1764,7 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
}
Datum
-timestamp_mi_span(PG_FUNCTION_ARGS)
+timestamp_mi_interval(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
@@ -1773,13 +1773,13 @@ timestamp_mi_span(PG_FUNCTION_ARGS)
tspan.month = -span->month;
tspan.time = -span->time;
- return DirectFunctionCall2(timestamp_pl_span,
+ return DirectFunctionCall2(timestamp_pl_interval,
TimestampGetDatum(timestamp),
PointerGetDatum(&tspan));
}
-/* timestamptz_pl_span()
+/* timestamptz_pl_interval()
* Add a interval to a timestamp with time zone data type.
* Note that interval has provisions for qualitative year/month
* units, so try to do the right thing with them.
@@ -1789,7 +1789,7 @@ timestamp_mi_span(PG_FUNCTION_ARGS)
* Lastly, add in the "quantitative time".
*/
Datum
-timestamptz_pl_span(PG_FUNCTION_ARGS)
+timestamptz_pl_interval(PG_FUNCTION_ARGS)
{
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
@@ -1844,7 +1844,7 @@ timestamptz_pl_span(PG_FUNCTION_ARGS)
}
Datum
-timestamptz_mi_span(PG_FUNCTION_ARGS)
+timestamptz_mi_interval(PG_FUNCTION_ARGS)
{
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
@@ -1853,7 +1853,7 @@ timestamptz_mi_span(PG_FUNCTION_ARGS)
tspan.month = -span->month;
tspan.time = -span->time;
- return DirectFunctionCall2(timestamptz_pl_span,
+ return DirectFunctionCall2(timestamptz_pl_interval,
TimestampGetDatum(timestamp),
PointerGetDatum(&tspan));
}