@@ -169,6 +169,7 @@ BuildTupleHashTableExt(PlanState *parent,
169
169
Size hash_mem_limit ;
170
170
MemoryContext oldcontext ;
171
171
bool allow_jit ;
172
+ uint32 hash_iv = 0 ;
172
173
173
174
Assert (nbuckets > 0 );
174
175
@@ -183,14 +184,13 @@ BuildTupleHashTableExt(PlanState *parent,
183
184
184
185
hashtable -> numCols = numCols ;
185
186
hashtable -> keyColIdx = keyColIdx ;
186
- hashtable -> tab_hash_funcs = hashfunctions ;
187
187
hashtable -> tab_collations = collations ;
188
188
hashtable -> tablecxt = tablecxt ;
189
189
hashtable -> tempcxt = tempcxt ;
190
190
hashtable -> entrysize = entrysize ;
191
191
hashtable -> tableslot = NULL ; /* will be made on first lookup */
192
192
hashtable -> inputslot = NULL ;
193
- hashtable -> in_hash_funcs = NULL ;
193
+ hashtable -> in_hash_expr = NULL ;
194
194
hashtable -> cur_eq_func = NULL ;
195
195
196
196
/*
@@ -202,9 +202,7 @@ BuildTupleHashTableExt(PlanState *parent,
202
202
* underestimated.
203
203
*/
204
204
if (use_variable_hash_iv )
205
- hashtable -> hash_iv = murmurhash32 (ParallelWorkerNumber );
206
- else
207
- hashtable -> hash_iv = 0 ;
205
+ hash_iv = murmurhash32 (ParallelWorkerNumber );
208
206
209
207
hashtable -> hashtab = tuplehash_create (metacxt , nbuckets , hashtable );
210
208
@@ -225,6 +223,16 @@ BuildTupleHashTableExt(PlanState *parent,
225
223
*/
226
224
allow_jit = metacxt != tablecxt ;
227
225
226
+ /* build hash ExprState for all columns */
227
+ hashtable -> tab_hash_expr = ExecBuildHash32FromAttrs (inputDesc ,
228
+ & TTSOpsMinimalTuple ,
229
+ hashfunctions ,
230
+ collations ,
231
+ numCols ,
232
+ keyColIdx ,
233
+ allow_jit ? parent : NULL ,
234
+ hash_iv );
235
+
228
236
/* build comparator for all columns */
229
237
/* XXX: should we support non-minimal tuples for the inputslot? */
230
238
hashtable -> tab_eq_func = ExecBuildGroupingEqual (inputDesc , inputDesc ,
@@ -316,7 +324,7 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
316
324
317
325
/* set up data needed by hash and match functions */
318
326
hashtable -> inputslot = slot ;
319
- hashtable -> in_hash_funcs = hashtable -> tab_hash_funcs ;
327
+ hashtable -> in_hash_expr = hashtable -> tab_hash_expr ;
320
328
hashtable -> cur_eq_func = hashtable -> tab_eq_func ;
321
329
322
330
local_hash = TupleHashTableHash_internal (hashtable -> hashtab , NULL );
@@ -342,7 +350,7 @@ TupleHashTableHash(TupleHashTable hashtable, TupleTableSlot *slot)
342
350
uint32 hash ;
343
351
344
352
hashtable -> inputslot = slot ;
345
- hashtable -> in_hash_funcs = hashtable -> tab_hash_funcs ;
353
+ hashtable -> in_hash_expr = hashtable -> tab_hash_expr ;
346
354
347
355
/* Need to run the hash functions in short-lived context */
348
356
oldContext = MemoryContextSwitchTo (hashtable -> tempcxt );
@@ -370,7 +378,7 @@ LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot,
370
378
371
379
/* set up data needed by hash and match functions */
372
380
hashtable -> inputslot = slot ;
373
- hashtable -> in_hash_funcs = hashtable -> tab_hash_funcs ;
381
+ hashtable -> in_hash_expr = hashtable -> tab_hash_expr ;
374
382
hashtable -> cur_eq_func = hashtable -> tab_eq_func ;
375
383
376
384
entry = LookupTupleHashEntry_internal (hashtable , slot , isnew , hash );
@@ -386,14 +394,14 @@ LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot,
386
394
* created if there's not a match. This is similar to the non-creating
387
395
* case of LookupTupleHashEntry, except that it supports cross-type
388
396
* comparisons, in which the given tuple is not of the same type as the
389
- * table entries. The caller must provide the hash functions to use for
390
- * the input tuple, as well as the equality functions , since these may be
397
+ * table entries. The caller must provide the hash ExprState to use for
398
+ * the input tuple, as well as the equality ExprState , since these may be
391
399
* different from the table's internal functions.
392
400
*/
393
401
TupleHashEntry
394
402
FindTupleHashEntry (TupleHashTable hashtable , TupleTableSlot * slot ,
395
403
ExprState * eqcomp ,
396
- FmgrInfo * hashfunctions )
404
+ ExprState * hashexpr )
397
405
{
398
406
TupleHashEntry entry ;
399
407
MemoryContext oldContext ;
@@ -404,7 +412,7 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
404
412
405
413
/* Set up data needed by hash and match functions */
406
414
hashtable -> inputslot = slot ;
407
- hashtable -> in_hash_funcs = hashfunctions ;
415
+ hashtable -> in_hash_expr = hashexpr ;
408
416
hashtable -> cur_eq_func = eqcomp ;
409
417
410
418
/* Search the hash table */
@@ -421,25 +429,24 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
421
429
* copied into the table.
422
430
*
423
431
* Also, the caller must select an appropriate memory context for running
424
- * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.)
432
+ * the hash functions.
425
433
*/
426
434
static uint32
427
435
TupleHashTableHash_internal (struct tuplehash_hash * tb ,
428
436
const MinimalTuple tuple )
429
437
{
430
438
TupleHashTable hashtable = (TupleHashTable ) tb -> private_data ;
431
- int numCols = hashtable -> numCols ;
432
- AttrNumber * keyColIdx = hashtable -> keyColIdx ;
433
- uint32 hashkey = hashtable -> hash_iv ;
439
+ uint32 hashkey ;
434
440
TupleTableSlot * slot ;
435
- FmgrInfo * hashfunctions ;
436
- int i ;
441
+ bool isnull ;
437
442
438
443
if (tuple == NULL )
439
444
{
440
445
/* Process the current input tuple for the table */
441
- slot = hashtable -> inputslot ;
442
- hashfunctions = hashtable -> in_hash_funcs ;
446
+ hashtable -> exprcontext -> ecxt_innertuple = hashtable -> inputslot ;
447
+ hashkey = DatumGetUInt32 (ExecEvalExpr (hashtable -> in_hash_expr ,
448
+ hashtable -> exprcontext ,
449
+ & isnull ));
443
450
}
444
451
else
445
452
{
@@ -449,38 +456,17 @@ TupleHashTableHash_internal(struct tuplehash_hash *tb,
449
456
* (this case never actually occurs due to the way simplehash.h is
450
457
* used, as the hash-value is stored in the entries)
451
458
*/
452
- slot = hashtable -> tableslot ;
459
+ slot = hashtable -> exprcontext -> ecxt_innertuple = hashtable -> tableslot ;
453
460
ExecStoreMinimalTuple (tuple , slot , false);
454
- hashfunctions = hashtable -> tab_hash_funcs ;
455
- }
456
-
457
- for (i = 0 ; i < numCols ; i ++ )
458
- {
459
- AttrNumber att = keyColIdx [i ];
460
- Datum attr ;
461
- bool isNull ;
462
-
463
- /* combine successive hashkeys by rotating */
464
- hashkey = pg_rotate_left32 (hashkey , 1 );
465
-
466
- attr = slot_getattr (slot , att , & isNull );
467
-
468
- if (!isNull ) /* treat nulls as having hash key 0 */
469
- {
470
- uint32 hkey ;
471
-
472
- hkey = DatumGetUInt32 (FunctionCall1Coll (& hashfunctions [i ],
473
- hashtable -> tab_collations [i ],
474
- attr ));
475
- hashkey ^= hkey ;
476
- }
461
+ hashkey = DatumGetUInt32 (ExecEvalExpr (hashtable -> tab_hash_expr ,
462
+ hashtable -> exprcontext ,
463
+ & isnull ));
477
464
}
478
465
479
466
/*
480
- * The way hashes are combined above, among each other and with the IV,
481
- * doesn't lead to good bit perturbation. As the IV's goal is to lead to
482
- * achieve that, perform a round of hashing of the combined hash -
483
- * resulting in near perfect perturbation.
467
+ * The hashing done above, even with an initial value, doesn't tend to
468
+ * result in good hash perturbation. Running the value produced above
469
+ * through murmurhash32 leads to near perfect hash perturbation.
484
470
*/
485
471
return murmurhash32 (hashkey );
486
472
}
0 commit comments