diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 2d1e7ff45aed985854f6000d2bec48b355681214..26fd570d672da3ecd9a5dfc54936fd3f64aa1e86 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.197 2009/03/15 20:31:19 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.198 2009/04/04 04:53:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2041,27 +2041,30 @@ timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
  *
  *		collate invalid interval at the end
  */
-static int
-interval_cmp_internal(Interval *interval1, Interval *interval2)
+static inline TimeOffset
+interval_cmp_value(const Interval *interval)
 {
-	TimeOffset	span1,
-				span2;
+	TimeOffset	span;
 
-	span1 = interval1->time;
-	span2 = interval2->time;
+	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);
 }
 
@@ -2128,32 +2131,24 @@ 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);
-	uint32		thash;
-	uint32		mhash;
+	Interval   *interval = PG_GETARG_INTERVAL_P(0);
+	TimeOffset	span = interval_cmp_value(interval);
 
-	/*
-	 * 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)));
+	return DirectFunctionCall1(hashint8, Int64GetDatumFast(span));
 #else
-	thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
-											 Float8GetDatumFast(key->time)));
+	return DirectFunctionCall1(hashfloat8, 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);
 }
 
 /* overlaps_timestamp() --- implements the SQL92 OVERLAPS operator.
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index f788e369e777b816fddc41a597e302ef1fd8490c..9effe61f42bf092cf38ffcc0666011f696301564 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -717,3 +717,16 @@ select interval '0:0:0.7', interval '@ 0.70 secs', interval '0.7 seconds';
  @ 0.7 secs | @ 0.7 secs | @ 0.7 secs
 (1 row)
 
+-- 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 0498739b839e998bedb5a23eb9768404ca2248d6..2a903a940dc2cfce93f0e3b5e8a8caa80bfd64eb 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -241,3 +241,7 @@ SET IntervalStyle to postgres_verbose;
 select interval '-10 mons -3 days +03:55:06.70';
 select interval '1 year 2 mons 3 days 04:05:06.699999';
 select interval '0:0:0.7', interval '@ 0.70 secs', interval '0.7 seconds'; 
+
+-- 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;