Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7af3a6f

Browse files
committed
Fix up hash functions for datetime datatypes so that they don't take
unwarranted liberties with int8 vs float8 values for these types. Specifically, be sure to apply either hashint8 or hashfloat8 depending on HAVE_INT64_TIMESTAMP. Per my gripe of even date.
1 parent ad9a99c commit 7af3a6f

File tree

9 files changed

+95
-41
lines changed

9 files changed

+95
-41
lines changed

src/backend/utils/adt/date.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.133 2007/06/15 20:56:50 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.134 2007/07/06 04:15:58 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1197,6 +1197,17 @@ time_cmp(PG_FUNCTION_ARGS)
11971197
PG_RETURN_INT32(0);
11981198
}
11991199

1200+
Datum
1201+
time_hash(PG_FUNCTION_ARGS)
1202+
{
1203+
/* We can use either hashint8 or hashfloat8 directly */
1204+
#ifdef HAVE_INT64_TIMESTAMP
1205+
return hashint8(fcinfo);
1206+
#else
1207+
return hashfloat8(fcinfo);
1208+
#endif
1209+
}
1210+
12001211
Datum
12011212
time_larger(PG_FUNCTION_ARGS)
12021213
{
@@ -1960,20 +1971,27 @@ timetz_cmp(PG_FUNCTION_ARGS)
19601971
PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
19611972
}
19621973

1963-
/*
1964-
* timetz, being an unusual size, needs a specialized hash function.
1965-
*/
19661974
Datum
19671975
timetz_hash(PG_FUNCTION_ARGS)
19681976
{
19691977
TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
1978+
uint32 thash;
19701979

19711980
/*
1972-
* Specify hash length as sizeof(double) + sizeof(int4), not as
1973-
* sizeof(TimeTzADT), so that any garbage pad bytes in the structure won't
1974-
* be included in the hash!
1981+
* To avoid any problems with padding bytes in the struct,
1982+
* we figure the field hashes separately and XOR them. This also
1983+
* provides a convenient framework for dealing with the fact that
1984+
* the time field might be either double or int64.
19751985
*/
1976-
return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->zone));
1986+
#ifdef HAVE_INT64_TIMESTAMP
1987+
thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
1988+
Int64GetDatumFast(key->time)));
1989+
#else
1990+
thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
1991+
Float8GetDatumFast(key->time)));
1992+
#endif
1993+
thash ^= DatumGetUInt32(hash_uint32(key->zone));
1994+
PG_RETURN_UINT32(thash);
19771995
}
19781996

19791997
Datum

src/backend/utils/adt/timestamp.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.178 2007/06/15 20:56:50 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.179 2007/07/06 04:15:59 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1839,6 +1839,17 @@ timestamp_cmp(PG_FUNCTION_ARGS)
18391839
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
18401840
}
18411841

1842+
Datum
1843+
timestamp_hash(PG_FUNCTION_ARGS)
1844+
{
1845+
/* We can use either hashint8 or hashfloat8 directly */
1846+
#ifdef HAVE_INT64_TIMESTAMP
1847+
return hashint8(fcinfo);
1848+
#else
1849+
return hashfloat8(fcinfo);
1850+
#endif
1851+
}
1852+
18421853

18431854
/*
18441855
* Crosstype comparison functions for timestamp vs timestamptz
@@ -2110,21 +2121,32 @@ interval_cmp(PG_FUNCTION_ARGS)
21102121
PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
21112122
}
21122123

2113-
/*
2114-
* interval, being an unusual size, needs a specialized hash function.
2115-
*/
21162124
Datum
21172125
interval_hash(PG_FUNCTION_ARGS)
21182126
{
21192127
Interval *key = PG_GETARG_INTERVAL_P(0);
2128+
uint32 thash;
2129+
uint32 mhash;
21202130

21212131
/*
2122-
* Specify hash length as sizeof(double) + sizeof(int4), not as
2123-
* sizeof(Interval), so that any garbage pad bytes in the structure won't
2124-
* be included in the hash!
2132+
* To avoid any problems with padding bytes in the struct,
2133+
* we figure the field hashes separately and XOR them. This also
2134+
* provides a convenient framework for dealing with the fact that
2135+
* the time field might be either double or int64.
21252136
*/
2126-
return hash_any((unsigned char *) key,
2127-
sizeof(key->time) + sizeof(key->day) + sizeof(key->month));
2137+
#ifdef HAVE_INT64_TIMESTAMP
2138+
thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2139+
Int64GetDatumFast(key->time)));
2140+
#else
2141+
thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
2142+
Float8GetDatumFast(key->time)));
2143+
#endif
2144+
thash ^= DatumGetUInt32(hash_uint32(key->day));
2145+
/* Shift so "k days" and "k months" don't hash to the same thing */
2146+
mhash = DatumGetUInt32(hash_uint32(key->month));
2147+
thash ^= mhash << 24;
2148+
thash ^= mhash >> 8;
2149+
PG_RETURN_UINT32(thash);
21282150
}
21292151

21302152
/* overlaps_timestamp() --- implements the SQL92 OVERLAPS operator.

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.413 2007/06/28 00:02:39 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.414 2007/07/06 04:15:59 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200706271
56+
#define CATALOG_VERSION_NO 200707051
5757

5858
#endif

src/include/catalog/pg_amproc.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
2323
* Portions Copyright (c) 1994, Regents of the University of California
2424
*
25-
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.65 2007/05/08 18:56:47 neilc Exp $
25+
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.66 2007/07/06 04:15:59 tgl Exp $
2626
*
2727
* NOTES
2828
* the genbki.sh script reads this file and generates .bki
@@ -147,11 +147,11 @@ DATA(insert ( 1987 19 19 1 455 ));
147147
DATA(insert ( 1990 26 26 1 453 ));
148148
DATA(insert ( 1992 30 30 1 457 ));
149149
DATA(insert ( 1995 25 25 1 400 ));
150-
DATA(insert ( 1997 1083 1083 1 452 ));
150+
DATA(insert ( 1997 1083 1083 1 1688 ));
151151
DATA(insert ( 1998 1700 1700 1 432 ));
152-
DATA(insert ( 1999 1184 1184 1 452 ));
152+
DATA(insert ( 1999 1184 1184 1 2039 ));
153153
DATA(insert ( 2001 1266 1266 1 1696 ));
154-
DATA(insert ( 2040 1114 1114 1 452 ));
154+
DATA(insert ( 2040 1114 1114 1 2039 ));
155155
DATA(insert ( 2222 16 16 1 454 ));
156156
DATA(insert ( 2223 17 17 1 456 ));
157157
DATA(insert ( 2224 22 22 1 398 ));

src/include/catalog/pg_proc.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.461 2007/06/28 00:02:39 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.462 2007/07/06 04:15:59 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2474,6 +2474,8 @@ DESCR("greater-than-or-equal");
24742474
DATA(insert OID = 1693 ( btboolcmp PGNSP PGUID 12 1 0 f f t f i 2 23 "16 16" _null_ _null_ _null_ btboolcmp - _null_ ));
24752475
DESCR("btree less-equal-greater");
24762476

2477+
DATA(insert OID = 1688 ( time_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "1083" _null_ _null_ _null_ time_hash - _null_ ));
2478+
DESCR("hash");
24772479
DATA(insert OID = 1696 ( timetz_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "1266" _null_ _null_ _null_ timetz_hash - _null_ ));
24782480
DESCR("hash");
24792481
DATA(insert OID = 1697 ( interval_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "1186" _null_ _null_ _null_ interval_hash - _null_ ));
@@ -3043,6 +3045,8 @@ DATA(insert OID = 2037 ( timezone PGNSP PGUID 12 1 0 f f t f v 2 1266 "25 126
30433045
DESCR("adjust time with time zone to new zone");
30443046
DATA(insert OID = 2038 ( timezone PGNSP PGUID 12 1 0 f f t f i 2 1266 "1186 1266" _null_ _null_ _null_ timetz_izone - _null_ ));
30453047
DESCR("adjust time with time zone to new zone");
3048+
DATA(insert OID = 2039 ( timestamp_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "1114" _null_ _null_ _null_ timestamp_hash - _null_ ));
3049+
DESCR("hash");
30463050
DATA(insert OID = 2041 ( overlaps PGNSP PGUID 12 1 0 f f f f i 4 16 "1114 1114 1114 1114" _null_ _null_ _null_ overlaps_timestamp - _null_ ));
30473051
DESCR("SQL92 interval comparison");
30483052
DATA(insert OID = 2042 ( overlaps PGNSP PGUID 14 1 0 f f f f i 4 16 "1114 1186 1114 1186" _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, ($3 + $4))" - _null_ ));

src/include/utils/date.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/date.h,v 1.37 2007/06/05 21:31:08 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/date.h,v 1.38 2007/07/06 04:16:00 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -148,6 +148,7 @@ extern Datum time_le(PG_FUNCTION_ARGS);
148148
extern Datum time_gt(PG_FUNCTION_ARGS);
149149
extern Datum time_ge(PG_FUNCTION_ARGS);
150150
extern Datum time_cmp(PG_FUNCTION_ARGS);
151+
extern Datum time_hash(PG_FUNCTION_ARGS);
151152
extern Datum overlaps_time(PG_FUNCTION_ARGS);
152153
extern Datum time_larger(PG_FUNCTION_ARGS);
153154
extern Datum time_smaller(PG_FUNCTION_ARGS);

src/include/utils/timestamp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.70 2007/06/05 21:31:08 tgl Exp $
9+
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.71 2007/07/06 04:16:00 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -211,6 +211,7 @@ extern Datum timestamp_ge(PG_FUNCTION_ARGS);
211211
extern Datum timestamp_gt(PG_FUNCTION_ARGS);
212212
extern Datum timestamp_finite(PG_FUNCTION_ARGS);
213213
extern Datum timestamp_cmp(PG_FUNCTION_ARGS);
214+
extern Datum timestamp_hash(PG_FUNCTION_ARGS);
214215
extern Datum timestamp_smaller(PG_FUNCTION_ARGS);
215216
extern Datum timestamp_larger(PG_FUNCTION_ARGS);
216217

src/test/regress/expected/opr_sanity.out

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -980,22 +980,30 @@ WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
980980
-- For hash we can also do a little better: the support routines must be
981981
-- of the form hash(lefttype) returns int4. There are several cases where
982982
-- we cheat and use a hash function that is physically compatible with the
983-
-- datatype even though there's no cast, so for now we can't check that.
984-
SELECT p1.amprocfamily, p1.amprocnum,
985-
p2.oid, p2.proname,
986-
p3.opfname
983+
-- datatype even though there's no cast, so this check does find a small
984+
-- number of entries.
985+
SELECT p1.amprocfamily, p1.amprocnum, p2.proname, p3.opfname
987986
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
988987
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
989988
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
990989
(amprocnum != 1
991990
OR proretset
992991
OR prorettype != 'int4'::regtype
993992
OR pronargs != 1
994-
-- OR NOT physically_coercible(amproclefttype, proargtypes[0])
995-
OR amproclefttype != amprocrighttype);
996-
amprocfamily | amprocnum | oid | proname | opfname
997-
--------------+-----------+-----+---------+---------
998-
(0 rows)
993+
OR NOT physically_coercible(amproclefttype, proargtypes[0])
994+
OR amproclefttype != amprocrighttype)
995+
ORDER BY 1;
996+
amprocfamily | amprocnum | proname | opfname
997+
--------------+-----------+----------------+--------------------
998+
435 | 1 | hashint4 | date_ops
999+
1999 | 1 | timestamp_hash | timestamptz_ops
1000+
2222 | 1 | hashchar | bool_ops
1001+
2223 | 1 | hashvarlena | bytea_ops
1002+
2225 | 1 | hashint4 | xid_ops
1003+
2226 | 1 | hashint4 | cid_ops
1004+
2229 | 1 | hashvarlena | text_pattern_ops
1005+
2231 | 1 | hashvarlena | bpchar_pattern_ops
1006+
(8 rows)
9991007

10001008
-- Support routines that are primary members of opfamilies must be immutable
10011009
-- (else it suggests that the index ordering isn't fixed). But cross-type

src/test/regress/sql/opr_sanity.sql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -790,20 +790,20 @@ WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
790790
-- For hash we can also do a little better: the support routines must be
791791
-- of the form hash(lefttype) returns int4. There are several cases where
792792
-- we cheat and use a hash function that is physically compatible with the
793-
-- datatype even though there's no cast, so for now we can't check that.
793+
-- datatype even though there's no cast, so this check does find a small
794+
-- number of entries.
794795

795-
SELECT p1.amprocfamily, p1.amprocnum,
796-
p2.oid, p2.proname,
797-
p3.opfname
796+
SELECT p1.amprocfamily, p1.amprocnum, p2.proname, p3.opfname
798797
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
799798
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
800799
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
801800
(amprocnum != 1
802801
OR proretset
803802
OR prorettype != 'int4'::regtype
804803
OR pronargs != 1
805-
-- OR NOT physically_coercible(amproclefttype, proargtypes[0])
806-
OR amproclefttype != amprocrighttype);
804+
OR NOT physically_coercible(amproclefttype, proargtypes[0])
805+
OR amproclefttype != amprocrighttype)
806+
ORDER BY 1;
807807

808808
-- Support routines that are primary members of opfamilies must be immutable
809809
-- (else it suggests that the index ordering isn't fixed). But cross-type

0 commit comments

Comments
 (0)