/* * Accept one tuple and append it to the tuplestore. * * Note that the input tuple is always copied; the caller need not save it. * * If the active read pointer is currently "at EOF", it remains so (the read * pointer implicitly advances along with the write pointer); otherwise the * read pointer is unchanged. Non-active read pointers do not move, which * means they are certain to not be "at EOF" immediately after puttuple. * This curious-seeming behavior is for the convenience of nodeMaterial.c and * nodeCtescan.c, which would otherwise need to do extra pointer repositioning * steps. * * tuplestore_puttupleslot() is a convenience routine to collect data from * a TupleTableSlot without an extra copy operation. */ void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot) { MinimalTuple tuple; /* * Form a MinimalTuple in working memory */ tuple = ExecCopySlotMinimalTuple(slot); USEMEM(state, GetMemoryChunkSpace(tuple)); tuplestore_puttuple_common(state, (void *) tuple); }
/* * Find or create a hashtable entry for the tuple group containing the * given tuple. The tuple must be the same type as the hashtable entries. * * If isnew is NULL, we do not create new entries; we return NULL if no * match is found. * * If isnew isn't NULL, then a new entry is created if no existing entry * matches. On return, *isnew is true if the entry is newly created, * false if it existed already. ->additional_data in the new entry has * been zeroed. */ TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew) { TupleHashEntryData *entry; MemoryContext oldContext; bool found; MinimalTuple key; /* Need to run the hash functions in short-lived context */ oldContext = MemoryContextSwitchTo(hashtable->tempcxt); /* set up data needed by hash and match functions */ hashtable->inputslot = slot; hashtable->in_hash_funcs = hashtable->tab_hash_funcs; hashtable->cur_eq_func = hashtable->tab_eq_func; key = NULL; /* flag to reference inputslot */ if (isnew) { entry = tuplehash_insert(hashtable->hashtab, key, &found); if (found) { /* found pre-existing entry */ *isnew = false; } else { /* created new entry */ *isnew = true; /* zero caller data */ entry->additional = NULL; MemoryContextSwitchTo(hashtable->tablecxt); /* Copy the first tuple into the table context */ entry->firstTuple = ExecCopySlotMinimalTuple(slot); } } else { entry = tuplehash_lookup(hashtable->hashtab, key); } MemoryContextSwitchTo(oldContext); return entry; }
/* * Find or create a hashtable entry for the tuple group containing the * given tuple. The tuple must be the same type as the hashtable entries. * * If isnew is NULL, we do not create new entries; we return NULL if no * match is found. * * If isnew isn't NULL, then a new entry is created if no existing entry * matches. On return, *isnew is true if the entry is newly created, * false if it existed already. ->additional_data in the new entry has * been zeroed. */ TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew) { TupleHashEntryData *entry; MemoryContext oldContext; bool found; MinimalTuple key; /* 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 */ hashtable->inputslot = slot; hashtable->in_hash_funcs = hashtable->tab_hash_funcs; hashtable->cur_eq_funcs = hashtable->tab_eq_funcs; key = NULL; /* flag to reference inputslot */ if (isnew) { entry = tuplehash_insert(hashtable->hashtab, key, &found); if (found) { /* found pre-existing entry */ *isnew = false; } else { /* created new entry */ *isnew = true; /* zero caller data */ entry->additional = NULL; MemoryContextSwitchTo(hashtable->tablecxt); /* Copy the first tuple into the table context */ entry->firstTuple = ExecCopySlotMinimalTuple(slot); } } else { entry = tuplehash_lookup(hashtable->hashtab, key); } MemoryContextSwitchTo(oldContext); return entry; }
/* * Find or create a hashtable entry for the tuple group containing the * given tuple. * * If isnew is NULL, we do not create new entries; we return NULL if no * match is found. * * If isnew isn't NULL, then a new entry is created if no existing entry * matches. On return, *isnew is true if the entry is newly created, * false if it existed already. Any extra space in a new entry has been * zeroed. */ TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew) { 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; 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; }