Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

hashfunc.c File Reference

#include "postgres.h"
#include "access/hash.h"
Include dependency graph for hashfunc.c:

Go to the source code of this file.

Defines

#define UINT32_ALIGN_MASK   (sizeof(uint32) - 1)
#define rot(x, k)   (((x)<<(k)) | ((x)>>(32-(k))))
#define mix(a, b, c)
#define final(a, b, c)

Functions

Datum hashchar (PG_FUNCTION_ARGS)
Datum hashint2 (PG_FUNCTION_ARGS)
Datum hashint4 (PG_FUNCTION_ARGS)
Datum hashint8 (PG_FUNCTION_ARGS)
Datum hashoid (PG_FUNCTION_ARGS)
Datum hashenum (PG_FUNCTION_ARGS)
Datum hashfloat4 (PG_FUNCTION_ARGS)
Datum hashfloat8 (PG_FUNCTION_ARGS)
Datum hashoidvector (PG_FUNCTION_ARGS)
Datum hashint2vector (PG_FUNCTION_ARGS)
Datum hashname (PG_FUNCTION_ARGS)
Datum hashtext (PG_FUNCTION_ARGS)
Datum hashvarlena (PG_FUNCTION_ARGS)
Datum hash_any (register const unsigned char *k, register int keylen)
Datum hash_uint32 (uint32 k)

Define Documentation

#define final (   a,
  b,
  c 
)
Value:
{ \
  c ^= b; c -= rot(b,14); \
  a ^= c; a -= rot(c,11); \
  b ^= a; b -= rot(a,25); \
  c ^= b; c -= rot(b,16); \
  a ^= c; a -= rot(c, 4); \
  b ^= a; b -= rot(a,14); \
  c ^= b; c -= rot(b,24); \
}

Definition at line 278 of file hashfunc.c.

#define mix (   a,
  b,
  c 
)
Value:
{ \
  a -= c;  a ^= rot(c, 4);  c += b; \
  b -= a;  b ^= rot(a, 6);  a += c; \
  c -= b;  c ^= rot(b, 8);  b += a; \
  a -= c;  a ^= rot(c,16);  c += b; \
  b -= a;  b ^= rot(a,19);  a += c; \
  c -= b;  c ^= rot(b, 4);  b += a; \
}

Definition at line 244 of file hashfunc.c.

Referenced by hash_any(), pgp_cfb_decrypt(), and pgp_cfb_encrypt().

#define rot (   x,
  k 
)    (((x)<<(k)) | ((x)>>(32-(k))))

Definition at line 210 of file hashfunc.c.

#define UINT32_ALIGN_MASK   (sizeof(uint32) - 1)

Definition at line 207 of file hashfunc.c.

Referenced by hash_any().


Function Documentation

Datum hash_any ( register const unsigned char *  k,
register int  keylen 
)

Definition at line 305 of file hashfunc.c.

References mix, UINT32_ALIGN_MASK, and UInt32GetDatum.

Referenced by AppendJumble(), bms_hash_value(), citext_hash(), hash_numeric(), hashbpchar(), hashfloat4(), hashfloat8(), hashinet(), hashint2vector(), hashmacaddr(), hashname(), hashoidvector(), hashtext(), hashvarlena(), hstore_hash(), lexeme_hash(), pgss_hash_string(), pgss_post_parse_analyze(), sepgsql_avc_hash(), string_hash(), tag_hash(), and uuid_hash().

{
    register uint32 a,
                b,
                c,
                len;

    /* Set up the internal state */
    len = keylen;
    a = b = c = 0x9e3779b9 + len + 3923095;

    /* If the source pointer is word-aligned, we use word-wide fetches */
    if (((intptr_t) k & UINT32_ALIGN_MASK) == 0)
    {
        /* Code path for aligned source data */
        register const uint32 *ka = (const uint32 *) k;

        /* handle most of the key */
        while (len >= 12)
        {
            a += ka[0];
            b += ka[1];
            c += ka[2];
            mix(a, b, c);
            ka += 3;
            len -= 12;
        }

        /* handle the last 11 bytes */
        k = (const unsigned char *) ka;
#ifdef WORDS_BIGENDIAN
        switch (len)
        {
            case 11:
                c += ((uint32) k[10] << 8);
                /* fall through */
            case 10:
                c += ((uint32) k[9] << 16);
                /* fall through */
            case 9:
                c += ((uint32) k[8] << 24);
                /* the lowest byte of c is reserved for the length */
                /* fall through */
            case 8:
                b += ka[1];
                a += ka[0];
                break;
            case 7:
                b += ((uint32) k[6] << 8);
                /* fall through */
            case 6:
                b += ((uint32) k[5] << 16);
                /* fall through */
            case 5:
                b += ((uint32) k[4] << 24);
                /* fall through */
            case 4:
                a += ka[0];
                break;
            case 3:
                a += ((uint32) k[2] << 8);
                /* fall through */
            case 2:
                a += ((uint32) k[1] << 16);
                /* fall through */
            case 1:
                a += ((uint32) k[0] << 24);
                /* case 0: nothing left to add */
        }
#else                           /* !WORDS_BIGENDIAN */
        switch (len)
        {
            case 11:
                c += ((uint32) k[10] << 24);
                /* fall through */
            case 10:
                c += ((uint32) k[9] << 16);
                /* fall through */
            case 9:
                c += ((uint32) k[8] << 8);
                /* the lowest byte of c is reserved for the length */
                /* fall through */
            case 8:
                b += ka[1];
                a += ka[0];
                break;
            case 7:
                b += ((uint32) k[6] << 16);
                /* fall through */
            case 6:
                b += ((uint32) k[5] << 8);
                /* fall through */
            case 5:
                b += k[4];
                /* fall through */
            case 4:
                a += ka[0];
                break;
            case 3:
                a += ((uint32) k[2] << 16);
                /* fall through */
            case 2:
                a += ((uint32) k[1] << 8);
                /* fall through */
            case 1:
                a += k[0];
                /* case 0: nothing left to add */
        }
#endif   /* WORDS_BIGENDIAN */
    }
    else
    {
        /* Code path for non-aligned source data */

        /* handle most of the key */
        while (len >= 12)
        {
#ifdef WORDS_BIGENDIAN
            a += (k[3] + ((uint32) k[2] << 8) + ((uint32) k[1] << 16) + ((uint32) k[0] << 24));
            b += (k[7] + ((uint32) k[6] << 8) + ((uint32) k[5] << 16) + ((uint32) k[4] << 24));
            c += (k[11] + ((uint32) k[10] << 8) + ((uint32) k[9] << 16) + ((uint32) k[8] << 24));
#else                           /* !WORDS_BIGENDIAN */
            a += (k[0] + ((uint32) k[1] << 8) + ((uint32) k[2] << 16) + ((uint32) k[3] << 24));
            b += (k[4] + ((uint32) k[5] << 8) + ((uint32) k[6] << 16) + ((uint32) k[7] << 24));
            c += (k[8] + ((uint32) k[9] << 8) + ((uint32) k[10] << 16) + ((uint32) k[11] << 24));
#endif   /* WORDS_BIGENDIAN */
            mix(a, b, c);
            k += 12;
            len -= 12;
        }

        /* handle the last 11 bytes */
#ifdef WORDS_BIGENDIAN
        switch (len)            /* all the case statements fall through */
        {
            case 11:
                c += ((uint32) k[10] << 8);
            case 10:
                c += ((uint32) k[9] << 16);
            case 9:
                c += ((uint32) k[8] << 24);
                /* the lowest byte of c is reserved for the length */
            case 8:
                b += k[7];
            case 7:
                b += ((uint32) k[6] << 8);
            case 6:
                b += ((uint32) k[5] << 16);
            case 5:
                b += ((uint32) k[4] << 24);
            case 4:
                a += k[3];
            case 3:
                a += ((uint32) k[2] << 8);
            case 2:
                a += ((uint32) k[1] << 16);
            case 1:
                a += ((uint32) k[0] << 24);
                /* case 0: nothing left to add */
        }
#else                           /* !WORDS_BIGENDIAN */
        switch (len)            /* all the case statements fall through */
        {
            case 11:
                c += ((uint32) k[10] << 24);
            case 10:
                c += ((uint32) k[9] << 16);
            case 9:
                c += ((uint32) k[8] << 8);
                /* the lowest byte of c is reserved for the length */
            case 8:
                b += ((uint32) k[7] << 24);
            case 7:
                b += ((uint32) k[6] << 16);
            case 6:
                b += ((uint32) k[5] << 8);
            case 5:
                b += k[4];
            case 4:
                a += ((uint32) k[3] << 24);
            case 3:
                a += ((uint32) k[2] << 16);
            case 2:
                a += ((uint32) k[1] << 8);
            case 1:
                a += k[0];
                /* case 0: nothing left to add */
        }
#endif   /* WORDS_BIGENDIAN */
    }

    final(a, b, c);

    /* report the result */
    return UInt32GetDatum(c);
}

Datum hash_uint32 ( uint32  k  ) 

Definition at line 510 of file hashfunc.c.

References UInt32GetDatum.

Referenced by hash_range(), hashchar(), hashenum(), hashint2(), hashint4(), hashint8(), hashoid(), oid_hash(), pgss_hash_fn(), and timetz_hash().

{
    register uint32 a,
                b,
                c;

    a = b = c = 0x9e3779b9 + (uint32) sizeof(uint32) + 3923095;
    a += k;

    final(a, b, c);

    /* report the result */
    return UInt32GetDatum(c);
}

Datum hashchar ( PG_FUNCTION_ARGS   ) 

Definition at line 34 of file hashfunc.c.

References hash_uint32(), and PG_GETARG_CHAR.

{
    return hash_uint32((int32) PG_GETARG_CHAR(0));
}

Datum hashenum ( PG_FUNCTION_ARGS   ) 

Definition at line 78 of file hashfunc.c.

References hash_uint32(), and PG_GETARG_OID.

{
    return hash_uint32((uint32) PG_GETARG_OID(0));
}

Datum hashfloat4 ( PG_FUNCTION_ARGS   ) 

Definition at line 84 of file hashfunc.c.

References hash_any(), PG_GETARG_FLOAT4, and PG_RETURN_UINT32.

{
    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;

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

Datum hashfloat8 ( PG_FUNCTION_ARGS   ) 

Definition at line 110 of file hashfunc.c.

References hash_any(), PG_GETARG_FLOAT8, and PG_RETURN_UINT32.

Referenced by interval_hash(), time_hash(), timestamp_hash(), and timetz_hash().

{
    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);

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

Datum hashint2 ( PG_FUNCTION_ARGS   ) 

Definition at line 40 of file hashfunc.c.

References hash_uint32(), and PG_GETARG_INT16.

{
    return hash_uint32((int32) PG_GETARG_INT16(0));
}

Datum hashint2vector ( PG_FUNCTION_ARGS   ) 

Definition at line 134 of file hashfunc.c.

References int2vector::dim1, hash_any(), PG_GETARG_POINTER, and int2vector::values.

{
    int2vector *key = (int2vector *) PG_GETARG_POINTER(0);

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

Datum hashint4 ( PG_FUNCTION_ARGS   ) 

Definition at line 46 of file hashfunc.c.

References hash_uint32(), and PG_GETARG_INT32.

{
    return hash_uint32(PG_GETARG_INT32(0));
}

Datum hashint8 ( PG_FUNCTION_ARGS   ) 

Definition at line 52 of file hashfunc.c.

References hash_uint32(), PG_GETARG_INT64, and val.

Referenced by interval_hash(), time_hash(), timestamp_hash(), and timetz_hash().

{
    /*
     * 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 hashname ( PG_FUNCTION_ARGS   ) 

Definition at line 142 of file hashfunc.c.

References Assert, hash_any(), NAMEDATALEN, NameStr, and PG_GETARG_NAME.

{
    char       *key = NameStr(*PG_GETARG_NAME(0));
    int         keylen = strlen(key);

    Assert(keylen < NAMEDATALEN);       /* else it's not truncated correctly */

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

Datum hashoid ( PG_FUNCTION_ARGS   ) 

Definition at line 72 of file hashfunc.c.

References hash_uint32(), and PG_GETARG_OID.

{
    return hash_uint32((uint32) PG_GETARG_OID(0));
}

Datum hashoidvector ( PG_FUNCTION_ARGS   ) 

Definition at line 126 of file hashfunc.c.

References oidvector::dim1, hash_any(), PG_GETARG_POINTER, and oidvector::values.

{
    oidvector  *key = (oidvector *) PG_GETARG_POINTER(0);

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

Datum hashtext ( PG_FUNCTION_ARGS   ) 

Definition at line 153 of file hashfunc.c.

References hash_any(), PG_FREE_IF_COPY, PG_GETARG_TEXT_PP, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

{
    text       *key = PG_GETARG_TEXT_PP(0);
    Datum       result;

    /*
     * Note: this is currently identical in behavior to hashvarlena, but keep
     * it as a separate function in case we someday want to do something
     * different in non-C locales.  (See also hashbpchar, if so.)
     */
    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 hashvarlena ( PG_FUNCTION_ARGS   ) 

Definition at line 177 of file hashfunc.c.

References hash_any(), PG_FREE_IF_COPY, PG_GETARG_VARLENA_PP, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

{
    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;
}