88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/execGrouping.c,v 1.24 2007/01/30 01:33:36 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/execGrouping.c,v 1.25 2007/02/06 02:59:11 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -178,7 +178,7 @@ execTuplesUnequal(TupleTableSlot *slot1,
178178/*
179179 * execTuplesMatchPrepare
180180 * Look up the equality functions needed for execTuplesMatch or
181- * execTuplesUnequal.
181+ * execTuplesUnequal, given an array of equality operator OIDs .
182182 *
183183 * The result is a palloc'd array.
184184 */
@@ -208,6 +208,8 @@ execTuplesMatchPrepare(int numCols,
208208 * This is similar to execTuplesMatchPrepare, but we also need to find the
209209 * hash functions associated with the equality operators. *eqFunctions and
210210 * *hashFunctions receive the palloc'd result arrays.
211+ *
212+ * Note: we expect that the given operators are not cross-type comparisons.
211213 */
212214void
213215execTuplesHashPrepare (int numCols ,
@@ -232,7 +234,7 @@ execTuplesHashPrepare(int numCols,
232234 & left_hash_function , & right_hash_function ))
233235 elog (ERROR , "could not find hash function for hash operator %u" ,
234236 eq_opr );
235- /* For the moment, we 're not supporting cross-type cases here */
237+ /* We 're not supporting cross-type cases here */
236238 Assert (left_hash_function == right_hash_function );
237239 fmgr_info (eq_function , & (* eqFunctions )[i ]);
238240 fmgr_info (right_hash_function , & (* hashFunctions )[i ]);
@@ -259,7 +261,9 @@ execTuplesHashPrepare(int numCols,
259261 * tablecxt: memory context in which to store table and table entries
260262 * tempcxt: short-lived context for evaluation hash and comparison functions
261263 *
262- * The function arrays may be made with execTuplesHashPrepare().
264+ * The function arrays may be made with execTuplesHashPrepare(). Note they
265+ * are not cross-type functions, but expect to see the table datatype(s)
266+ * on both sides.
263267 *
264268 * Note that keyColIdx, eqfunctions, and hashfunctions must be allocated in
265269 * storage that will live as long as the hashtable does.
@@ -282,13 +286,15 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
282286
283287 hashtable -> numCols = numCols ;
284288 hashtable -> keyColIdx = keyColIdx ;
285- hashtable -> eqfunctions = eqfunctions ;
286- hashtable -> hashfunctions = hashfunctions ;
289+ hashtable -> tab_hash_funcs = hashfunctions ;
290+ hashtable -> tab_eq_funcs = eqfunctions ;
287291 hashtable -> tablecxt = tablecxt ;
288292 hashtable -> tempcxt = tempcxt ;
289293 hashtable -> entrysize = entrysize ;
290294 hashtable -> tableslot = NULL ; /* will be made on first lookup */
291295 hashtable -> inputslot = NULL ;
296+ hashtable -> in_hash_funcs = NULL ;
297+ hashtable -> cur_eq_funcs = NULL ;
292298
293299 MemSet (& hash_ctl , 0 , sizeof (hash_ctl ));
294300 hash_ctl .keysize = sizeof (TupleHashEntryData );
@@ -305,7 +311,7 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
305311
306312/*
307313 * Find or create a hashtable entry for the tuple group containing the
308- * given tuple.
314+ * given tuple. The tuple must be the same type as the hashtable entries.
309315 *
310316 * If isnew is NULL, we do not create new entries; we return NULL if no
311317 * match is found.
@@ -351,6 +357,9 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
351357 * invoke this code re-entrantly.
352358 */
353359 hashtable -> inputslot = slot ;
360+ hashtable -> in_hash_funcs = hashtable -> tab_hash_funcs ;
361+ hashtable -> cur_eq_funcs = hashtable -> tab_eq_funcs ;
362+
354363 saveCurHT = CurTupleHashTable ;
355364 CurTupleHashTable = hashtable ;
356365
@@ -394,6 +403,55 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
394403 return entry ;
395404}
396405
406+ /*
407+ * Search for a hashtable entry matching the given tuple. No entry is
408+ * created if there's not a match. This is similar to the non-creating
409+ * case of LookupTupleHashEntry, except that it supports cross-type
410+ * comparisons, in which the given tuple is not of the same type as the
411+ * table entries. The caller must provide the hash functions to use for
412+ * the input tuple, as well as the equality functions, since these may be
413+ * different from the table's internal functions.
414+ */
415+ TupleHashEntry
416+ FindTupleHashEntry (TupleHashTable hashtable , TupleTableSlot * slot ,
417+ FmgrInfo * eqfunctions ,
418+ FmgrInfo * hashfunctions )
419+ {
420+ TupleHashEntry entry ;
421+ MemoryContext oldContext ;
422+ TupleHashTable saveCurHT ;
423+ TupleHashEntryData dummy ;
424+
425+ /* Need to run the hash functions in short-lived context */
426+ oldContext = MemoryContextSwitchTo (hashtable -> tempcxt );
427+
428+ /*
429+ * Set up data needed by hash and match functions
430+ *
431+ * We save and restore CurTupleHashTable just in case someone manages to
432+ * invoke this code re-entrantly.
433+ */
434+ hashtable -> inputslot = slot ;
435+ hashtable -> in_hash_funcs = hashfunctions ;
436+ hashtable -> cur_eq_funcs = eqfunctions ;
437+
438+ saveCurHT = CurTupleHashTable ;
439+ CurTupleHashTable = hashtable ;
440+
441+ /* Search the hash table */
442+ dummy .firstTuple = NULL ; /* flag to reference inputslot */
443+ entry = (TupleHashEntry ) hash_search (hashtable -> hashtab ,
444+ & dummy ,
445+ HASH_FIND ,
446+ NULL );
447+
448+ CurTupleHashTable = saveCurHT ;
449+
450+ MemoryContextSwitchTo (oldContext );
451+
452+ return entry ;
453+ }
454+
397455/*
398456 * Compute the hash value for a tuple
399457 *
@@ -418,20 +476,23 @@ TupleHashTableHash(const void *key, Size keysize)
418476 TupleHashTable hashtable = CurTupleHashTable ;
419477 int numCols = hashtable -> numCols ;
420478 AttrNumber * keyColIdx = hashtable -> keyColIdx ;
479+ FmgrInfo * hashfunctions ;
421480 uint32 hashkey = 0 ;
422481 int i ;
423482
424483 if (tuple == NULL )
425484 {
426485 /* Process the current input tuple for the table */
427486 slot = hashtable -> inputslot ;
487+ hashfunctions = hashtable -> in_hash_funcs ;
428488 }
429489 else
430490 {
431491 /* Process a tuple already stored in the table */
432492 /* (this case never actually occurs in current dynahash.c code) */
433493 slot = hashtable -> tableslot ;
434494 ExecStoreMinimalTuple (tuple , slot , false);
495+ hashfunctions = hashtable -> tab_hash_funcs ;
435496 }
436497
437498 for (i = 0 ; i < numCols ; i ++ )
@@ -449,7 +510,7 @@ TupleHashTableHash(const void *key, Size keysize)
449510 {
450511 uint32 hkey ;
451512
452- hkey = DatumGetUInt32 (FunctionCall1 (& hashtable -> hashfunctions [i ],
513+ hkey = DatumGetUInt32 (FunctionCall1 (& hashfunctions [i ],
453514 attr ));
454515 hashkey ^= hkey ;
455516 }
@@ -493,11 +554,12 @@ TupleHashTableMatch(const void *key1, const void *key2, Size keysize)
493554 Assert (tuple2 == NULL );
494555 slot2 = hashtable -> inputslot ;
495556
496- if (execTuplesMatch (slot1 ,
497- slot2 ,
557+ /* For crosstype comparisons, the inputslot must be first */
558+ if (execTuplesMatch (slot2 ,
559+ slot1 ,
498560 hashtable -> numCols ,
499561 hashtable -> keyColIdx ,
500- hashtable -> eqfunctions ,
562+ hashtable -> cur_eq_funcs ,
501563 hashtable -> tempcxt ))
502564 return 0 ;
503565 else
0 commit comments