Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/access/hash/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 10 kB image not shown  

Quelle  hashfunc.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * hashfunc.c
 *   Support functions for hash access method.
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/backend/access/hash/hashfunc.c
 *
 * NOTES
 *   These functions are stored in pg_amproc.  For each operator class
 *   defined for hash indexes, they compute the hash value of the argument.
 *
 *   Additional hash functions appear in /utils/adt/ files for various
 *   specialized datatypes.
 *
 *   It is expected that every bit of a hash function's 32-bit result is
 *   as random as every other; failure to ensure this is likely to lead
 *   to poor performance of hash joins, for example.  In most cases a hash
 *   function should use hash_any() or its variant hash_uint32().
 *-------------------------------------------------------------------------
 */


#include "postgres.h"

#include "common/hashfn.h"
#include "utils/builtins.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
#include "utils/pg_locale.h"
#include "varatt.h"

/*
 * Datatype-specific hash functions.
 *
 * These support both hash indexes and hash joins.
 *
 * NOTE: some of these are also used by catcache operations, without
 * any direct connection to hash indexes.  Also, the common hash_any
 * routine is also used by dynahash tables.
 */


/* Note: this is used for both "char" and boolean datatypes */
Datum
hashchar(PG_FUNCTION_ARGS)
{
 return hash_uint32((int32) PG_GETARG_CHAR(0));
}

Datum
hashcharextended(PG_FUNCTION_ARGS)
{
 return hash_uint32_extended((int32) PG_GETARG_CHAR(0), PG_GETARG_INT64(1));
}

Datum
hashint2(PG_FUNCTION_ARGS)
{
 return hash_uint32((int32) PG_GETARG_INT16(0));
}

Datum
hashint2extended(PG_FUNCTION_ARGS)
{
 return hash_uint32_extended((int32) PG_GETARG_INT16(0), PG_GETARG_INT64(1));
}

Datum
hashint4(PG_FUNCTION_ARGS)
{
 return hash_uint32(PG_GETARG_INT32(0));
}

Datum
hashint4extended(PG_FUNCTION_ARGS)
{
 return hash_uint32_extended(PG_GETARG_INT32(0), PG_GETARG_INT64(1));
}

Datum
hashint8(PG_FUNCTION_ARGS)
{
 /*
  * The idea here is to produce a hash value compatible with the values
  * produced by hashint4 and hashint2 for logically equal inputs; this is
  * necessary to support cross-type hash joins across these input types.
  * Since all three types are signed, we can xor the high half of the int8
  * value if the sign is positive, or the complement of the high half when
  * the sign is negative.
 */

 int64  val = PG_GETARG_INT64(0);
 uint32  lohalf = (uint32) val;
 uint32  hihalf = (uint32) (val >> 32);

 lohalf ^= (val >= 0) ? hihalf : ~hihalf;

 return hash_uint32(lohalf);
}

Datum
hashint8extended(PG_FUNCTION_ARGS)
{
 /* Same approach as hashint8 */
 int64  val = PG_GETARG_INT64(0);
 uint32  lohalf = (uint32) val;
 uint32  hihalf = (uint32) (val >> 32);

 lohalf ^= (val >= 0) ? hihalf : ~hihalf;

 return hash_uint32_extended(lohalf, PG_GETARG_INT64(1));
}

Datum
hashoid(PG_FUNCTION_ARGS)
{
 return hash_uint32((uint32) PG_GETARG_OID(0));
}

Datum
hashoidextended(PG_FUNCTION_ARGS)
{
 return hash_uint32_extended((uint32) PG_GETARG_OID(0), PG_GETARG_INT64(1));
}

Datum
hashenum(PG_FUNCTION_ARGS)
{
 return hash_uint32((uint32) PG_GETARG_OID(0));
}

Datum
hashenumextended(PG_FUNCTION_ARGS)
{
 return hash_uint32_extended((uint32) PG_GETARG_OID(0), PG_GETARG_INT64(1));
}

Datum
hashfloat4(PG_FUNCTION_ARGS)
{
 float4  key = PG_GETARG_FLOAT4(0);
 float8  key8;

 /*
  * On IEEE-float machines, minus zero and zero have different bit patterns
  * but should compare as equal.  We must ensure that they have the same
  * hash value, which is most reliably done this way:
 */

 if (key == (float4) 0)
  PG_RETURN_UINT32(0);

 /*
  * To support cross-type hashing of float8 and float4, we want to return
  * the same hash value hashfloat8 would produce for an equal float8 value.
  * So, widen the value to float8 and hash that.  (We must do this rather
  * than have hashfloat8 try to narrow its value to float4; that could fail
  * on overflow.)
 */

 key8 = key;

 /*
  * Similarly, NaNs can have different bit patterns but they should all
  * compare as equal.  For backwards-compatibility reasons we force them to
  * have the hash value of a standard float8 NaN.  (You'd think we could
  * replace key with a float4 NaN and then widen it; but on some old
  * platforms, that way produces a different bit pattern.)
 */

 if (isnan(key8))
  key8 = get_float8_nan();

 return hash_any((unsigned char *) &key8, sizeof(key8));
}

Datum
hashfloat4extended(PG_FUNCTION_ARGS)
{
 float4  key = PG_GETARG_FLOAT4(0);
 uint64  seed = PG_GETARG_INT64(1);
 float8  key8;

 /* Same approach as hashfloat4 */
 if (key == (float4) 0)
  PG_RETURN_UINT64(seed);
 key8 = key;
 if (isnan(key8))
  key8 = get_float8_nan();

 return hash_any_extended((unsigned char *) &key8, sizeof(key8), seed);
}

Datum
hashfloat8(PG_FUNCTION_ARGS)
{
 float8  key = PG_GETARG_FLOAT8(0);

 /*
  * On IEEE-float machines, minus zero and zero have different bit patterns
  * but should compare as equal.  We must ensure that they have the same
  * hash value, which is most reliably done this way:
 */

 if (key == (float8) 0)
  PG_RETURN_UINT32(0);

 /*
  * Similarly, NaNs can have different bit patterns but they should all
  * compare as equal.  For backwards-compatibility reasons we force them to
  * have the hash value of a standard NaN.
 */

 if (isnan(key))
  key = get_float8_nan();

 return hash_any((unsigned char *) &key, sizeof(key));
}

Datum
hashfloat8extended(PG_FUNCTION_ARGS)
{
 float8  key = PG_GETARG_FLOAT8(0);
 uint64  seed = PG_GETARG_INT64(1);

 /* Same approach as hashfloat8 */
 if (key == (float8) 0)
  PG_RETURN_UINT64(seed);
 if (isnan(key))
  key = get_float8_nan();

 return hash_any_extended((unsigned char *) &key, sizeof(key), seed);
}

Datum
hashoidvector(PG_FUNCTION_ARGS)
{
 oidvector  *key = (oidvector *) PG_GETARG_POINTER(0);

 check_valid_oidvector(key);
 return hash_any((unsigned char *) key->values, key->dim1 * sizeof(Oid));
}

Datum
hashoidvectorextended(PG_FUNCTION_ARGS)
{
 oidvector  *key = (oidvector *) PG_GETARG_POINTER(0);

 check_valid_oidvector(key);
 return hash_any_extended((unsigned char *) key->values,
        key->dim1 * sizeof(Oid),
        PG_GETARG_INT64(1));
}

Datum
hashname(PG_FUNCTION_ARGS)
{
 char    *key = NameStr(*PG_GETARG_NAME(0));

 return hash_any((unsigned char *) key, strlen(key));
}

Datum
hashnameextended(PG_FUNCTION_ARGS)
{
 char    *key = NameStr(*PG_GETARG_NAME(0));

 return hash_any_extended((unsigned char *) key, strlen(key),
        PG_GETARG_INT64(1));
}

Datum
hashtext(PG_FUNCTION_ARGS)
{
 text    *key = PG_GETARG_TEXT_PP(0);
 Oid   collid = PG_GET_COLLATION();
 pg_locale_t mylocale;
 Datum  result;

 if (!collid)
  ereport(ERROR,
    (errcode(ERRCODE_INDETERMINATE_COLLATION),
     errmsg("could not determine which collation to use for string hashing"),
     errhint("Use the COLLATE clause to set the collation explicitly.")));

 mylocale = pg_newlocale_from_collation(collid);

 if (mylocale->deterministic)
 {
  result = hash_any((unsigned char *) VARDATA_ANY(key),
        VARSIZE_ANY_EXHDR(key));
 }
 else
 {
  Size  bsize,
     rsize;
  char    *buf;
  const char *keydata = VARDATA_ANY(key);
  size_t  keylen = VARSIZE_ANY_EXHDR(key);


  bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
  buf = palloc(bsize + 1);

  rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);

  /* the second call may return a smaller value than the first */
  if (rsize > bsize)
   elog(ERROR, "pg_strnxfrm() returned unexpected result");

  /*
   * In principle, there's no reason to include the terminating NUL
   * character in the hash, but it was done before and the behavior must
   * be preserved.
 */

  result = hash_any((uint8_t *) buf, bsize + 1);

  pfree(buf);
 }

 /* Avoid leaking memory for toasted inputs */
 PG_FREE_IF_COPY(key, 0);

 return result;
}

Datum
hashtextextended(PG_FUNCTION_ARGS)
{
 text    *key = PG_GETARG_TEXT_PP(0);
 Oid   collid = PG_GET_COLLATION();
 pg_locale_t mylocale;
 Datum  result;

 if (!collid)
  ereport(ERROR,
    (errcode(ERRCODE_INDETERMINATE_COLLATION),
     errmsg("could not determine which collation to use for string hashing"),
     errhint("Use the COLLATE clause to set the collation explicitly.")));

 mylocale = pg_newlocale_from_collation(collid);

 if (mylocale->deterministic)
 {
  result = hash_any_extended((unsigned char *) VARDATA_ANY(key),
           VARSIZE_ANY_EXHDR(key),
           PG_GETARG_INT64(1));
 }
 else
 {
  Size  bsize,
     rsize;
  char    *buf;
  const char *keydata = VARDATA_ANY(key);
  size_t  keylen = VARSIZE_ANY_EXHDR(key);

  bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
  buf = palloc(bsize + 1);

  rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);

  /* the second call may return a smaller value than the first */
  if (rsize > bsize)
   elog(ERROR, "pg_strnxfrm() returned unexpected result");

  /*
   * In principle, there's no reason to include the terminating NUL
   * character in the hash, but it was done before and the behavior must
   * be preserved.
 */

  result = hash_any_extended((uint8_t *) buf, bsize + 1,
           PG_GETARG_INT64(1));

  pfree(buf);
 }

 PG_FREE_IF_COPY(key, 0);

 return result;
}

/*
 * hashvarlena() can be used for any varlena datatype in which there are
 * no non-significant bits, ie, distinct bitpatterns never compare as equal.
 *
 * (However, you need to define an SQL-level wrapper function around it with
 * the concrete input data type; otherwise hashvalidate() won't accept it.
 * Moreover, at least for built-in types, a C-level wrapper function is also
 * recommended; otherwise, the opr_sanity test will get upset.)
 */

Datum
hashvarlena(PG_FUNCTION_ARGS)
{
 struct varlena *key = PG_GETARG_VARLENA_PP(0);
 Datum  result;

 result = hash_any((unsigned char *) VARDATA_ANY(key),
       VARSIZE_ANY_EXHDR(key));

 /* Avoid leaking memory for toasted inputs */
 PG_FREE_IF_COPY(key, 0);

 return result;
}

Datum
hashvarlenaextended(PG_FUNCTION_ARGS)
{
 struct varlena *key = PG_GETARG_VARLENA_PP(0);
 Datum  result;

 result = hash_any_extended((unsigned char *) VARDATA_ANY(key),
          VARSIZE_ANY_EXHDR(key),
          PG_GETARG_INT64(1));

 PG_FREE_IF_COPY(key, 0);

 return result;
}

Datum
hashbytea(PG_FUNCTION_ARGS)
{
 return hashvarlena(fcinfo);
}

Datum
hashbyteaextended(PG_FUNCTION_ARGS)
{
 return hashvarlenaextended(fcinfo);
}

Messung V0.5 in Prozent
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.