Header And Logo

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

Functions | Variables

execGrouping.c File Reference

#include "postgres.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for execGrouping.c:

Go to the source code of this file.

Functions

static uint32 TupleHashTableHash (const void *key, Size keysize)
static int TupleHashTableMatch (const void *key1, const void *key2, Size keysize)
bool execTuplesMatch (TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
bool execTuplesUnequal (TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
FmgrInfoexecTuplesMatchPrepare (int numCols, Oid *eqOperators)
void execTuplesHashPrepare (int numCols, Oid *eqOperators, FmgrInfo **eqFunctions, FmgrInfo **hashFunctions)
TupleHashTable BuildTupleHashTable (int numCols, AttrNumber *keyColIdx, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions, long nbuckets, Size entrysize, MemoryContext tablecxt, MemoryContext tempcxt)
TupleHashEntry LookupTupleHashEntry (TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew)
TupleHashEntry FindTupleHashEntry (TupleHashTable hashtable, TupleTableSlot *slot, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions)

Variables

static TupleHashTable CurTupleHashTable = NULL

Function Documentation

TupleHashTable BuildTupleHashTable ( int  numCols,
AttrNumber keyColIdx,
FmgrInfo eqfunctions,
FmgrInfo hashfunctions,
long  nbuckets,
Size  entrysize,
MemoryContext  tablecxt,
MemoryContext  tempcxt 
)

Definition at line 275 of file execGrouping.c.

References Assert, TupleHashTableData::cur_eq_funcs, HASHCTL::entrysize, TupleHashTableData::entrysize, HASHCTL::hash, HASH_COMPARE, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_FUNCTION, TupleHashTableData::hashtab, HASHCTL::hcxt, TupleHashTableData::in_hash_funcs, TupleHashTableData::inputslot, TupleHashTableData::keyColIdx, HASHCTL::keysize, HASHCTL::match, MemoryContextAlloc(), MemSet, Min, TupleHashTableData::numCols, TupleHashTableData::tab_eq_funcs, TupleHashTableData::tab_hash_funcs, TupleHashTableData::tablecxt, TupleHashTableData::tableslot, TupleHashTableData::tempcxt, and work_mem.

Referenced by build_hash_table(), and buildSubPlanHash().

{
    TupleHashTable hashtable;
    HASHCTL     hash_ctl;

    Assert(nbuckets > 0);
    Assert(entrysize >= sizeof(TupleHashEntryData));

    /* Limit initial table size request to not more than work_mem */
    nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));

    hashtable = (TupleHashTable) MemoryContextAlloc(tablecxt,
                                                 sizeof(TupleHashTableData));

    hashtable->numCols = numCols;
    hashtable->keyColIdx = keyColIdx;
    hashtable->tab_hash_funcs = hashfunctions;
    hashtable->tab_eq_funcs = eqfunctions;
    hashtable->tablecxt = tablecxt;
    hashtable->tempcxt = tempcxt;
    hashtable->entrysize = entrysize;
    hashtable->tableslot = NULL;    /* will be made on first lookup */
    hashtable->inputslot = NULL;
    hashtable->in_hash_funcs = NULL;
    hashtable->cur_eq_funcs = NULL;

    MemSet(&hash_ctl, 0, sizeof(hash_ctl));
    hash_ctl.keysize = sizeof(TupleHashEntryData);
    hash_ctl.entrysize = entrysize;
    hash_ctl.hash = TupleHashTableHash;
    hash_ctl.match = TupleHashTableMatch;
    hash_ctl.hcxt = tablecxt;
    hashtable->hashtab = hash_create("TupleHashTable", nbuckets,
                                     &hash_ctl,
                    HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);

    return hashtable;
}

void execTuplesHashPrepare ( int  numCols,
Oid eqOperators,
FmgrInfo **  eqFunctions,
FmgrInfo **  hashFunctions 
)

Definition at line 218 of file execGrouping.c.

References Assert, elog, ERROR, fmgr_info(), get_op_hash_functions(), get_opcode(), i, and palloc().

Referenced by ExecInitAgg(), ExecInitRecursiveUnion(), and ExecInitSetOp().

{
    int         i;

    *eqFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
    *hashFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));

    for (i = 0; i < numCols; i++)
    {
        Oid         eq_opr = eqOperators[i];
        Oid         eq_function;
        Oid         left_hash_function;
        Oid         right_hash_function;

        eq_function = get_opcode(eq_opr);
        if (!get_op_hash_functions(eq_opr,
                                   &left_hash_function, &right_hash_function))
            elog(ERROR, "could not find hash function for hash operator %u",
                 eq_opr);
        /* We're not supporting cross-type cases here */
        Assert(left_hash_function == right_hash_function);
        fmgr_info(eq_function, &(*eqFunctions)[i]);
        fmgr_info(right_hash_function, &(*hashFunctions)[i]);
    }
}

bool execTuplesMatch ( TupleTableSlot slot1,
TupleTableSlot slot2,
int  numCols,
AttrNumber matchColIdx,
FmgrInfo eqfunctions,
MemoryContext  evalContext 
)

Definition at line 54 of file execGrouping.c.

References DatumGetBool, FunctionCall2, i, MemoryContextReset(), MemoryContextSwitchTo(), and slot_getattr().

Referenced by agg_retrieve_direct(), are_peers(), ExecGroup(), ExecUnique(), process_ordered_aggregate_multi(), setop_retrieve_direct(), spool_tuples(), and TupleHashTableMatch().

{
    MemoryContext oldContext;
    bool        result;
    int         i;

    /* Reset and switch into the temp context. */
    MemoryContextReset(evalContext);
    oldContext = MemoryContextSwitchTo(evalContext);

    /*
     * We cannot report a match without checking all the fields, but we can
     * report a non-match as soon as we find unequal fields.  So, start
     * comparing at the last field (least significant sort key). That's the
     * most likely to be different if we are dealing with sorted input.
     */
    result = true;

    for (i = numCols; --i >= 0;)
    {
        AttrNumber  att = matchColIdx[i];
        Datum       attr1,
                    attr2;
        bool        isNull1,
                    isNull2;

        attr1 = slot_getattr(slot1, att, &isNull1);

        attr2 = slot_getattr(slot2, att, &isNull2);

        if (isNull1 != isNull2)
        {
            result = false;     /* one null and one not; they aren't equal */
            break;
        }

        if (isNull1)
            continue;           /* both are null, treat as equal */

        /* Apply the type-specific equality function */

        if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
                                        attr1, attr2)))
        {
            result = false;     /* they aren't equal */
            break;
        }
    }

    MemoryContextSwitchTo(oldContext);

    return result;
}

FmgrInfo* execTuplesMatchPrepare ( int  numCols,
Oid eqOperators 
)

Definition at line 189 of file execGrouping.c.

References fmgr_info(), get_opcode(), i, and palloc().

Referenced by ExecInitAgg(), ExecInitGroup(), ExecInitSetOp(), ExecInitUnique(), and ExecInitWindowAgg().

{
    FmgrInfo   *eqFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
    int         i;

    for (i = 0; i < numCols; i++)
    {
        Oid         eq_opr = eqOperators[i];
        Oid         eq_function;

        eq_function = get_opcode(eq_opr);
        fmgr_info(eq_function, &eqFunctions[i]);
    }

    return eqFunctions;
}

bool execTuplesUnequal ( TupleTableSlot slot1,
TupleTableSlot slot2,
int  numCols,
AttrNumber matchColIdx,
FmgrInfo eqfunctions,
MemoryContext  evalContext 
)

Definition at line 124 of file execGrouping.c.

References DatumGetBool, FunctionCall2, i, MemoryContextReset(), MemoryContextSwitchTo(), and slot_getattr().

Referenced by findPartialMatch().

{
    MemoryContext oldContext;
    bool        result;
    int         i;

    /* Reset and switch into the temp context. */
    MemoryContextReset(evalContext);
    oldContext = MemoryContextSwitchTo(evalContext);

    /*
     * We cannot report a match without checking all the fields, but we can
     * report a non-match as soon as we find unequal fields.  So, start
     * comparing at the last field (least significant sort key). That's the
     * most likely to be different if we are dealing with sorted input.
     */
    result = false;

    for (i = numCols; --i >= 0;)
    {
        AttrNumber  att = matchColIdx[i];
        Datum       attr1,
                    attr2;
        bool        isNull1,
                    isNull2;

        attr1 = slot_getattr(slot1, att, &isNull1);

        if (isNull1)
            continue;           /* can't prove anything here */

        attr2 = slot_getattr(slot2, att, &isNull2);

        if (isNull2)
            continue;           /* can't prove anything here */

        /* Apply the type-specific equality function */

        if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
                                        attr1, attr2)))
        {
            result = true;      /* they are unequal */
            break;
        }
    }

    MemoryContextSwitchTo(oldContext);

    return result;
}

TupleHashEntry FindTupleHashEntry ( TupleHashTable  hashtable,
TupleTableSlot slot,
FmgrInfo eqfunctions,
FmgrInfo hashfunctions 
)

Definition at line 422 of file execGrouping.c.

References TupleHashTableData::cur_eq_funcs, TupleHashEntryData::firstTuple, HASH_FIND, hash_search(), TupleHashTableData::hashtab, TupleHashTableData::in_hash_funcs, TupleHashTableData::inputslot, MemoryContextSwitchTo(), NULL, and TupleHashTableData::tempcxt.

Referenced by ExecHashSubPlan().

{
    TupleHashEntry entry;
    MemoryContext oldContext;
    TupleHashTable saveCurHT;
    TupleHashEntryData dummy;

    /* Need to run the hash functions in short-lived context */
    oldContext = MemoryContextSwitchTo(hashtable->tempcxt);

    /*
     * Set up data needed by hash and match functions
     *
     * We save and restore CurTupleHashTable just in case someone manages to
     * invoke this code re-entrantly.
     */
    hashtable->inputslot = slot;
    hashtable->in_hash_funcs = hashfunctions;
    hashtable->cur_eq_funcs = eqfunctions;

    saveCurHT = CurTupleHashTable;
    CurTupleHashTable = hashtable;

    /* Search the hash table */
    dummy.firstTuple = NULL;    /* flag to reference inputslot */
    entry = (TupleHashEntry) hash_search(hashtable->hashtab,
                                         &dummy,
                                         HASH_FIND,
                                         NULL);

    CurTupleHashTable = saveCurHT;

    MemoryContextSwitchTo(oldContext);

    return entry;
}

TupleHashEntry LookupTupleHashEntry ( TupleHashTable  hashtable,
TupleTableSlot slot,
bool isnew 
)

Definition at line 331 of file execGrouping.c.

References CreateTupleDescCopy(), TupleHashTableData::cur_eq_funcs, TupleHashTableData::entrysize, ExecCopySlotMinimalTuple(), TupleHashEntryData::firstTuple, HASH_ENTER, HASH_FIND, hash_search(), TupleHashTableData::hashtab, TupleHashTableData::in_hash_funcs, TupleHashTableData::inputslot, MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), MemSet, NULL, TupleHashTableData::tab_eq_funcs, TupleHashTableData::tab_hash_funcs, TupleHashTableData::tablecxt, TupleHashTableData::tableslot, TupleHashTableData::tempcxt, and TupleTableSlot::tts_tupleDescriptor.

Referenced by buildSubPlanHash(), ExecRecursiveUnion(), lookup_hash_entry(), and setop_fill_hash_table().

{
    TupleHashEntry entry;
    MemoryContext oldContext;
    TupleHashTable saveCurHT;
    TupleHashEntryData dummy;
    bool        found;

    /* If first time through, clone the input slot to make table slot */
    if (hashtable->tableslot == NULL)
    {
        TupleDesc   tupdesc;

        oldContext = MemoryContextSwitchTo(hashtable->tablecxt);

        /*
         * We copy the input tuple descriptor just for safety --- we assume
         * all input tuples will have equivalent descriptors.
         */
        tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
        hashtable->tableslot = MakeSingleTupleTableSlot(tupdesc);
        MemoryContextSwitchTo(oldContext);
    }

    /* Need to run the hash functions in short-lived context */
    oldContext = MemoryContextSwitchTo(hashtable->tempcxt);

    /*
     * Set up data needed by hash and match functions
     *
     * We save and restore CurTupleHashTable just in case someone manages to
     * invoke this code re-entrantly.
     */
    hashtable->inputslot = slot;
    hashtable->in_hash_funcs = hashtable->tab_hash_funcs;
    hashtable->cur_eq_funcs = hashtable->tab_eq_funcs;

    saveCurHT = CurTupleHashTable;
    CurTupleHashTable = hashtable;

    /* Search the hash table */
    dummy.firstTuple = NULL;    /* flag to reference inputslot */
    entry = (TupleHashEntry) hash_search(hashtable->hashtab,
                                         &dummy,
                                         isnew ? HASH_ENTER : HASH_FIND,
                                         &found);

    if (isnew)
    {
        if (found)
        {
            /* found pre-existing entry */
            *isnew = false;
        }
        else
        {
            /*
             * created new entry
             *
             * Zero any caller-requested space in the entry.  (This zaps the
             * "key data" dynahash.c copied into the new entry, but we don't
             * care since we're about to overwrite it anyway.)
             */
            MemSet(entry, 0, hashtable->entrysize);

            /* Copy the first tuple into the table context */
            MemoryContextSwitchTo(hashtable->tablecxt);
            entry->firstTuple = ExecCopySlotMinimalTuple(slot);

            *isnew = true;
        }
    }

    CurTupleHashTable = saveCurHT;

    MemoryContextSwitchTo(oldContext);

    return entry;
}

static uint32 TupleHashTableHash ( const void *  key,
Size  keysize 
) [static]

Definition at line 478 of file execGrouping.c.

References DatumGetUInt32, ExecStoreMinimalTuple(), FunctionCall1, i, TupleHashTableData::in_hash_funcs, TupleHashTableData::inputslot, TupleHashTableData::keyColIdx, NULL, TupleHashTableData::numCols, slot_getattr(), TupleHashTableData::tab_hash_funcs, and TupleHashTableData::tableslot.

{
    MinimalTuple tuple = ((const TupleHashEntryData *) key)->firstTuple;
    TupleTableSlot *slot;
    TupleHashTable hashtable = CurTupleHashTable;
    int         numCols = hashtable->numCols;
    AttrNumber *keyColIdx = hashtable->keyColIdx;
    FmgrInfo   *hashfunctions;
    uint32      hashkey = 0;
    int         i;

    if (tuple == NULL)
    {
        /* Process the current input tuple for the table */
        slot = hashtable->inputslot;
        hashfunctions = hashtable->in_hash_funcs;
    }
    else
    {
        /* Process a tuple already stored in the table */
        /* (this case never actually occurs in current dynahash.c code) */
        slot = hashtable->tableslot;
        ExecStoreMinimalTuple(tuple, slot, false);
        hashfunctions = hashtable->tab_hash_funcs;
    }

    for (i = 0; i < numCols; i++)
    {
        AttrNumber  att = keyColIdx[i];
        Datum       attr;
        bool        isNull;

        /* rotate hashkey left 1 bit at each step */
        hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);

        attr = slot_getattr(slot, att, &isNull);

        if (!isNull)            /* treat nulls as having hash key 0 */
        {
            uint32      hkey;

            hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i],
                                                attr));
            hashkey ^= hkey;
        }
    }

    return hashkey;
}

static int TupleHashTableMatch ( const void *  key1,
const void *  key2,
Size  keysize 
) [static]

Definition at line 540 of file execGrouping.c.

References Assert, TupleHashTableData::cur_eq_funcs, ExecStoreMinimalTuple(), execTuplesMatch(), TupleHashTableData::inputslot, TupleHashTableData::keyColIdx, NULL, TupleHashTableData::numCols, TupleHashTableData::tableslot, and TupleHashTableData::tempcxt.

{
    MinimalTuple tuple1 = ((const TupleHashEntryData *) key1)->firstTuple;

#ifdef USE_ASSERT_CHECKING
    MinimalTuple tuple2 = ((const TupleHashEntryData *) key2)->firstTuple;
#endif
    TupleTableSlot *slot1;
    TupleTableSlot *slot2;
    TupleHashTable hashtable = CurTupleHashTable;

    /*
     * We assume that dynahash.c will only ever call us with the first
     * argument being an actual table entry, and the second argument being
     * LookupTupleHashEntry's dummy TupleHashEntryData.  The other direction
     * could be supported too, but is not currently used by dynahash.c.
     */
    Assert(tuple1 != NULL);
    slot1 = hashtable->tableslot;
    ExecStoreMinimalTuple(tuple1, slot1, false);
    Assert(tuple2 == NULL);
    slot2 = hashtable->inputslot;

    /* For crosstype comparisons, the inputslot must be first */
    if (execTuplesMatch(slot2,
                        slot1,
                        hashtable->numCols,
                        hashtable->keyColIdx,
                        hashtable->cur_eq_funcs,
                        hashtable->tempcxt))
        return 0;
    else
        return 1;
}


Variable Documentation

Definition at line 27 of file execGrouping.c.