diff options
author | David Rowley <drowley@postgresql.org> | 2021-11-24 10:07:38 +1300 |
---|---|---|
committer | David Rowley <drowley@postgresql.org> | 2021-11-24 10:07:38 +1300 |
commit | 6c32c0977783fae217b5eaa1d22d26c96e5b0085 (patch) | |
tree | 8ec10704a9486236f84ffc3122de21bb595793cf /src/backend/utils/adt/datum.c | |
parent | 0fdf67476ccbcc60bba185fd08a90b95cd91ce2d (diff) | |
download | postgresql-6c32c0977783fae217b5eaa1d22d26c96e5b0085.tar.gz postgresql-6c32c0977783fae217b5eaa1d22d26c96e5b0085.zip |
Allow Memoize to operate in binary comparison mode
Memoize would always use the hash equality operator for the cache key
types to determine if the current set of parameters were the same as some
previously cached set. Certain types such as floating points where -0.0
and +0.0 differ in their binary representation but are classed as equal by
the hash equality operator may cause problems as unless the join uses the
same operator it's possible that whichever join operator is being used
would be able to distinguish the two values. In which case we may
accidentally return in the incorrect rows out of the cache.
To fix this here we add a binary mode to Memoize to allow it to the
current set of parameters to previously cached values by comparing
bit-by-bit rather than logically using the hash equality operator. This
binary mode is always used for LATERAL joins and it's used for normal
joins when any of the join operators are not hashable.
Reported-by: Tom Lane
Author: David Rowley
Discussion: https://postgr.es/m/3004308.1632952496@sss.pgh.pa.us
Backpatch-through: 14, where Memoize was added
Diffstat (limited to 'src/backend/utils/adt/datum.c')
-rw-r--r-- | src/backend/utils/adt/datum.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index 6a317fc0a6d..2f229395744 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -43,6 +43,7 @@ #include "postgres.h" #include "access/detoast.h" +#include "common/hashfn.h" #include "fmgr.h" #include "utils/builtins.h" #include "utils/datum.h" @@ -325,6 +326,57 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen) } /*------------------------------------------------------------------------- + * datum_image_hash + * + * Generate a hash value based on the binary representation of 'value'. Most + * use cases will want to use the hash function specific to the Datum's type, + * however, some corner cases require generating a hash value based on the + * actual bits rather than the logical value. + *------------------------------------------------------------------------- + */ +uint32 +datum_image_hash(Datum value, bool typByVal, int typLen) +{ + Size len; + uint32 result; + + if (typByVal) + result = hash_bytes((unsigned char *) &value, sizeof(Datum)); + else if (typLen > 0) + result = hash_bytes((unsigned char *) DatumGetPointer(value), typLen); + else if (typLen == -1) + { + struct varlena *val; + + len = toast_raw_datum_size(value); + + val = PG_DETOAST_DATUM_PACKED(value); + + result = hash_bytes((unsigned char *) VARDATA_ANY(val), len - VARHDRSZ); + + /* Only free memory if it's a copy made here. */ + if ((Pointer) val != (Pointer) value) + pfree(val); + } + else if (typLen == -2) + { + char *s; + + s = DatumGetCString(value); + len = strlen(s) + 1; + + result = hash_bytes((unsigned char *) s, len); + } + else + { + elog(ERROR, "unexpected typLen: %d", typLen); + result = 0; /* keep compiler quiet */ + } + + return result; +} + +/*------------------------------------------------------------------------- * btequalimage * * Generic "equalimage" support function. |