@@ -168,6 +168,12 @@ static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *
168
168
static Datum ExecJustAssignInnerVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
169
169
static Datum ExecJustAssignOuterVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
170
170
static Datum ExecJustAssignScanVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
171
+ static Datum ExecJustHashInnerVarWithIV (ExprState * state , ExprContext * econtext , bool * isnull );
172
+ static Datum ExecJustHashOuterVar (ExprState * state , ExprContext * econtext , bool * isnull );
173
+ static Datum ExecJustHashInnerVar (ExprState * state , ExprContext * econtext , bool * isnull );
174
+ static Datum ExecJustHashOuterVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
175
+ static Datum ExecJustHashInnerVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
176
+ static Datum ExecJustHashOuterVarStrict (ExprState * state , ExprContext * econtext , bool * isnull );
171
177
172
178
/* execution helper functions */
173
179
static pg_attribute_always_inline void ExecAggPlainTransByVal (AggState * aggstate ,
@@ -273,7 +279,51 @@ ExecReadyInterpretedExpr(ExprState *state)
273
279
* the full interpreter is a measurable overhead for these, and these
274
280
* patterns occur often enough to be worth optimizing.
275
281
*/
276
- if (state -> steps_len == 3 )
282
+ if (state -> steps_len == 5 )
283
+ {
284
+ ExprEvalOp step0 = state -> steps [0 ].opcode ;
285
+ ExprEvalOp step1 = state -> steps [1 ].opcode ;
286
+ ExprEvalOp step2 = state -> steps [2 ].opcode ;
287
+ ExprEvalOp step3 = state -> steps [3 ].opcode ;
288
+
289
+ if (step0 == EEOP_INNER_FETCHSOME &&
290
+ step1 == EEOP_HASHDATUM_SET_INITVAL &&
291
+ step2 == EEOP_INNER_VAR &&
292
+ step3 == EEOP_HASHDATUM_NEXT32 )
293
+ {
294
+ state -> evalfunc_private = (void * ) ExecJustHashInnerVarWithIV ;
295
+ return ;
296
+ }
297
+ }
298
+ else if (state -> steps_len == 4 )
299
+ {
300
+ ExprEvalOp step0 = state -> steps [0 ].opcode ;
301
+ ExprEvalOp step1 = state -> steps [1 ].opcode ;
302
+ ExprEvalOp step2 = state -> steps [2 ].opcode ;
303
+
304
+ if (step0 == EEOP_OUTER_FETCHSOME &&
305
+ step1 == EEOP_OUTER_VAR &&
306
+ step2 == EEOP_HASHDATUM_FIRST )
307
+ {
308
+ state -> evalfunc_private = (void * ) ExecJustHashOuterVar ;
309
+ return ;
310
+ }
311
+ else if (step0 == EEOP_INNER_FETCHSOME &&
312
+ step1 == EEOP_INNER_VAR &&
313
+ step2 == EEOP_HASHDATUM_FIRST )
314
+ {
315
+ state -> evalfunc_private = (void * ) ExecJustHashInnerVar ;
316
+ return ;
317
+ }
318
+ else if (step0 == EEOP_OUTER_FETCHSOME &&
319
+ step1 == EEOP_OUTER_VAR &&
320
+ step2 == EEOP_HASHDATUM_FIRST_STRICT )
321
+ {
322
+ state -> evalfunc_private = (void * ) ExecJustHashOuterVarStrict ;
323
+ return ;
324
+ }
325
+ }
326
+ else if (state -> steps_len == 3 )
277
327
{
278
328
ExprEvalOp step0 = state -> steps [0 ].opcode ;
279
329
ExprEvalOp step1 = state -> steps [1 ].opcode ;
@@ -321,6 +371,18 @@ ExecReadyInterpretedExpr(ExprState *state)
321
371
state -> evalfunc_private = ExecJustApplyFuncToCase ;
322
372
return ;
323
373
}
374
+ else if (step0 == EEOP_INNER_VAR &&
375
+ step1 == EEOP_HASHDATUM_FIRST )
376
+ {
377
+ state -> evalfunc_private = (void * ) ExecJustHashInnerVarVirt ;
378
+ return ;
379
+ }
380
+ else if (step0 == EEOP_OUTER_VAR &&
381
+ step1 == EEOP_HASHDATUM_FIRST )
382
+ {
383
+ state -> evalfunc_private = (void * ) ExecJustHashOuterVarVirt ;
384
+ return ;
385
+ }
324
386
}
325
387
else if (state -> steps_len == 2 )
326
388
{
@@ -2484,6 +2546,148 @@ ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2484
2546
return ExecJustAssignVarVirtImpl (state , econtext -> ecxt_scantuple , isnull );
2485
2547
}
2486
2548
2549
+ /*
2550
+ * implementation for hashing an inner Var, seeding with an initial value.
2551
+ */
2552
+ static Datum
2553
+ ExecJustHashInnerVarWithIV (ExprState * state , ExprContext * econtext ,
2554
+ bool * isnull )
2555
+ {
2556
+ ExprEvalStep * fetchop = & state -> steps [0 ];
2557
+ ExprEvalStep * setivop = & state -> steps [1 ];
2558
+ ExprEvalStep * innervar = & state -> steps [2 ];
2559
+ ExprEvalStep * hashop = & state -> steps [3 ];
2560
+ FunctionCallInfo fcinfo = hashop -> d .hashdatum .fcinfo_data ;
2561
+ int attnum = innervar -> d .var .attnum ;
2562
+ uint32 hashkey ;
2563
+
2564
+ CheckOpSlotCompatibility (fetchop , econtext -> ecxt_innertuple );
2565
+ slot_getsomeattrs (econtext -> ecxt_innertuple , fetchop -> d .fetch .last_var );
2566
+
2567
+ fcinfo -> args [0 ].value = econtext -> ecxt_innertuple -> tts_values [attnum ];
2568
+ fcinfo -> args [0 ].isnull = econtext -> ecxt_innertuple -> tts_isnull [attnum ];
2569
+
2570
+ hashkey = DatumGetUInt32 (setivop -> d .hashdatum_initvalue .init_value );
2571
+ hashkey = pg_rotate_left32 (hashkey , 1 );
2572
+
2573
+ if (!fcinfo -> args [0 ].isnull )
2574
+ {
2575
+ uint32 hashvalue ;
2576
+
2577
+ hashvalue = DatumGetUInt32 (hashop -> d .hashdatum .fn_addr (fcinfo ));
2578
+ hashkey = hashkey ^ hashvalue ;
2579
+ }
2580
+
2581
+ * isnull = false;
2582
+ return UInt32GetDatum (hashkey );
2583
+ }
2584
+
2585
+ /* implementation of ExecJustHash(Inner|Outer)Var */
2586
+ static pg_attribute_always_inline Datum
2587
+ ExecJustHashVarImpl (ExprState * state , TupleTableSlot * slot , bool * isnull )
2588
+ {
2589
+ ExprEvalStep * fetchop = & state -> steps [0 ];
2590
+ ExprEvalStep * var = & state -> steps [1 ];
2591
+ ExprEvalStep * hashop = & state -> steps [2 ];
2592
+ FunctionCallInfo fcinfo = hashop -> d .hashdatum .fcinfo_data ;
2593
+ int attnum = var -> d .var .attnum ;
2594
+
2595
+ CheckOpSlotCompatibility (fetchop , slot );
2596
+ slot_getsomeattrs (slot , fetchop -> d .fetch .last_var );
2597
+
2598
+ fcinfo -> args [0 ].value = slot -> tts_values [attnum ];
2599
+ fcinfo -> args [0 ].isnull = slot -> tts_isnull [attnum ];
2600
+
2601
+ * isnull = false;
2602
+
2603
+ if (!fcinfo -> args [0 ].isnull )
2604
+ return DatumGetUInt32 (hashop -> d .hashdatum .fn_addr (fcinfo ));
2605
+ else
2606
+ return (Datum ) 0 ;
2607
+ }
2608
+
2609
+ /* implementation for hashing an outer Var */
2610
+ static Datum
2611
+ ExecJustHashOuterVar (ExprState * state , ExprContext * econtext , bool * isnull )
2612
+ {
2613
+ return ExecJustHashVarImpl (state , econtext -> ecxt_outertuple , isnull );
2614
+ }
2615
+
2616
+ /* implementation for hashing an inner Var */
2617
+ static Datum
2618
+ ExecJustHashInnerVar (ExprState * state , ExprContext * econtext , bool * isnull )
2619
+ {
2620
+ return ExecJustHashVarImpl (state , econtext -> ecxt_innertuple , isnull );
2621
+ }
2622
+
2623
+ /* implementation of ExecJustHash(Inner|Outer)VarVirt */
2624
+ static pg_attribute_always_inline Datum
2625
+ ExecJustHashVarVirtImpl (ExprState * state , TupleTableSlot * slot , bool * isnull )
2626
+ {
2627
+ ExprEvalStep * var = & state -> steps [0 ];
2628
+ ExprEvalStep * hashop = & state -> steps [1 ];
2629
+ FunctionCallInfo fcinfo = hashop -> d .hashdatum .fcinfo_data ;
2630
+ int attnum = var -> d .var .attnum ;
2631
+
2632
+ fcinfo -> args [0 ].value = slot -> tts_values [attnum ];
2633
+ fcinfo -> args [0 ].isnull = slot -> tts_isnull [attnum ];
2634
+
2635
+ * isnull = false;
2636
+
2637
+ if (!fcinfo -> args [0 ].isnull )
2638
+ return DatumGetUInt32 (hashop -> d .hashdatum .fn_addr (fcinfo ));
2639
+ else
2640
+ return (Datum ) 0 ;
2641
+ }
2642
+
2643
+ /* Like ExecJustHashInnerVar, optimized for virtual slots */
2644
+ static Datum
2645
+ ExecJustHashInnerVarVirt (ExprState * state , ExprContext * econtext ,
2646
+ bool * isnull )
2647
+ {
2648
+ return ExecJustHashVarVirtImpl (state , econtext -> ecxt_innertuple , isnull );
2649
+ }
2650
+
2651
+ /* Like ExecJustHashOuterVar, optimized for virtual slots */
2652
+ static Datum
2653
+ ExecJustHashOuterVarVirt (ExprState * state , ExprContext * econtext ,
2654
+ bool * isnull )
2655
+ {
2656
+ return ExecJustHashVarVirtImpl (state , econtext -> ecxt_outertuple , isnull );
2657
+ }
2658
+
2659
+ /*
2660
+ * implementation for hashing an outer Var. Returns NULL on NULL input.
2661
+ */
2662
+ static Datum
2663
+ ExecJustHashOuterVarStrict (ExprState * state , ExprContext * econtext ,
2664
+ bool * isnull )
2665
+ {
2666
+ ExprEvalStep * fetchop = & state -> steps [0 ];
2667
+ ExprEvalStep * var = & state -> steps [1 ];
2668
+ ExprEvalStep * hashop = & state -> steps [2 ];
2669
+ FunctionCallInfo fcinfo = hashop -> d .hashdatum .fcinfo_data ;
2670
+ int attnum = var -> d .var .attnum ;
2671
+
2672
+ CheckOpSlotCompatibility (fetchop , econtext -> ecxt_outertuple );
2673
+ slot_getsomeattrs (econtext -> ecxt_outertuple , fetchop -> d .fetch .last_var );
2674
+
2675
+ fcinfo -> args [0 ].value = econtext -> ecxt_outertuple -> tts_values [attnum ];
2676
+ fcinfo -> args [0 ].isnull = econtext -> ecxt_outertuple -> tts_isnull [attnum ];
2677
+
2678
+ if (!fcinfo -> args [0 ].isnull )
2679
+ {
2680
+ * isnull = false;
2681
+ return DatumGetUInt32 (hashop -> d .hashdatum .fn_addr (fcinfo ));
2682
+ }
2683
+ else
2684
+ {
2685
+ /* return NULL on NULL input */
2686
+ * isnull = true;
2687
+ return (Datum ) 0 ;
2688
+ }
2689
+ }
2690
+
2487
2691
#if defined(EEO_USE_COMPUTED_GOTO )
2488
2692
/*
2489
2693
* Comparator used when building address->opcode lookup table for
0 commit comments