aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/timestamp.c67
-rw-r--r--src/test/regress/expected/interval.out13
-rw-r--r--src/test/regress/sql/interval.sql6
3 files changed, 52 insertions, 34 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 5a08e584d95..74b56631aed 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.184.2.1 2008/07/07 18:09:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.184.2.2 2009/04/04 04:53:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2029,32 +2029,36 @@ timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
*
* collate invalid interval at the end
*/
-static int
-interval_cmp_internal(Interval *interval1, Interval *interval2)
-{
#ifdef HAVE_INT64_TIMESTAMP
- int64 span1,
- span2;
+typedef int64 TimeOffset;
#else
- double span1,
- span2;
+typedef double TimeOffset;
#endif
- span1 = interval1->time;
- span2 = interval2->time;
+static inline TimeOffset
+interval_cmp_value(const Interval *interval)
+{
+ TimeOffset span;
+
+ span = interval->time;
#ifdef HAVE_INT64_TIMESTAMP
- span1 += interval1->month * INT64CONST(30) * USECS_PER_DAY;
- span1 += interval1->day * INT64CONST(24) * USECS_PER_HOUR;
- span2 += interval2->month * INT64CONST(30) * USECS_PER_DAY;
- span2 += interval2->day * INT64CONST(24) * USECS_PER_HOUR;
+ span += interval->month * INT64CONST(30) * USECS_PER_DAY;
+ span += interval->day * INT64CONST(24) * USECS_PER_HOUR;
#else
- span1 += interval1->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY);
- span1 += interval1->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR);
- span2 += interval2->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY);
- span2 += interval2->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR);
+ span += interval->month * ((double) DAYS_PER_MONTH * SECS_PER_DAY);
+ span += interval->day * ((double) HOURS_PER_DAY * SECS_PER_HOUR);
#endif
+ return span;
+}
+
+static int
+interval_cmp_internal(Interval *interval1, Interval *interval2)
+{
+ TimeOffset span1 = interval_cmp_value(interval1);
+ TimeOffset span2 = interval_cmp_value(interval2);
+
return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
}
@@ -2121,31 +2125,28 @@ interval_cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
}
+/*
+ * Hashing for intervals
+ *
+ * We must produce equal hashvals for values that interval_cmp_internal()
+ * considers equal. So, compute the net span the same way it does,
+ * and then hash that, using either int64 or float8 hashing.
+ */
Datum
interval_hash(PG_FUNCTION_ARGS)
{
- Interval *key = PG_GETARG_INTERVAL_P(0);
+ Interval *interval = PG_GETARG_INTERVAL_P(0);
+ TimeOffset span = interval_cmp_value(interval);
uint32 thash;
- uint32 mhash;
- /*
- * To avoid any problems with padding bytes in the struct, we figure the
- * field hashes separately and XOR them. This also provides a convenient
- * framework for dealing with the fact that the time field might be either
- * double or int64.
- */
#ifdef HAVE_INT64_TIMESTAMP
thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
- Int64GetDatumFast(key->time)));
+ Int64GetDatumFast(span)));
#else
thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
- Float8GetDatumFast(key->time)));
+ Float8GetDatumFast(span)));
#endif
- thash ^= DatumGetUInt32(hash_uint32(key->day));
- /* Shift so "k days" and "k months" don't hash to the same thing */
- mhash = DatumGetUInt32(hash_uint32(key->month));
- thash ^= mhash << 24;
- thash ^= mhash >> 8;
+
PG_RETURN_UINT32(thash);
}
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index 72a031df5f1..5f3531430bb 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -349,3 +349,16 @@ SELECT '5.5 seconds 3 milliseconds'::interval; -- error
ERROR: invalid input syntax for type interval: "5.5 seconds 3 milliseconds"
SELECT '1:20:05 5 microseconds'::interval; -- error
ERROR: invalid input syntax for type interval: "1:20:05 5 microseconds"
+-- check that '30 days' equals '1 month' according to the hash function
+select '30 days'::interval = '1 month'::interval as t;
+ t
+---
+ t
+(1 row)
+
+select interval_hash('30 days'::interval) = interval_hash('1 month'::interval) as t;
+ t
+---
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index d081bf1ffed..3541d68cc8b 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -126,4 +126,8 @@ SELECT '3 days 5 milliseconds'::interval;
SELECT '1 second 2 seconds'::interval; -- error
SELECT '10 milliseconds 20 milliseconds'::interval; -- error
SELECT '5.5 seconds 3 milliseconds'::interval; -- error
-SELECT '1:20:05 5 microseconds'::interval; -- error \ No newline at end of file
+SELECT '1:20:05 5 microseconds'::interval; -- error
+
+-- check that '30 days' equals '1 month' according to the hash function
+select '30 days'::interval = '1 month'::interval as t;
+select interval_hash('30 days'::interval) = interval_hash('1 month'::interval) as t;