@@ -168,6 +168,12 @@ static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *
168168static Datum ExecJustAssignInnerVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
169169static Datum ExecJustAssignOuterVarVirt (ExprState * state , ExprContext * econtext , bool * isnull );
170170static 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 );
171177
172178/* execution helper functions */
173179static pg_attribute_always_inline void ExecAggPlainTransByVal (AggState * aggstate ,
@@ -273,7 +279,51 @@ ExecReadyInterpretedExpr(ExprState *state)
273279 * the full interpreter is a measurable overhead for these, and these
274280 * patterns occur often enough to be worth optimizing.
275281 */
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 )
277327 {
278328 ExprEvalOp step0 = state -> steps [0 ].opcode ;
279329 ExprEvalOp step1 = state -> steps [1 ].opcode ;
@@ -321,6 +371,18 @@ ExecReadyInterpretedExpr(ExprState *state)
321371 state -> evalfunc_private = ExecJustApplyFuncToCase ;
322372 return ;
323373 }
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+ }
324386 }
325387 else if (state -> steps_len == 2 )
326388 {
@@ -2484,6 +2546,148 @@ ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
24842546 return ExecJustAssignVarVirtImpl (state , econtext -> ecxt_scantuple , isnull );
24852547}
24862548
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+
24872691#if defined(EEO_USE_COMPUTED_GOTO )
24882692/*
24892693 * Comparator used when building address->opcode lookup table for
0 commit comments