@@ -345,25 +345,42 @@ var_eq_const(VariableStatData *vardata, Oid operator,
345
345
STATISTIC_KIND_MCV , InvalidOid ,
346
346
ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS ))
347
347
{
348
+ LOCAL_FCINFO (fcinfo , 2 );
348
349
FmgrInfo eqproc ;
349
350
350
351
fmgr_info (opfuncoid , & eqproc );
351
352
353
+ /*
354
+ * Save a few cycles by setting up the fcinfo struct just once.
355
+ * Using FunctionCallInvoke directly also avoids failure if the
356
+ * eqproc returns NULL, though really equality functions should
357
+ * never do that.
358
+ */
359
+ InitFunctionCallInfoData (* fcinfo , & eqproc , 2 , sslot .stacoll ,
360
+ NULL , NULL );
361
+ fcinfo -> args [0 ].isnull = false;
362
+ fcinfo -> args [1 ].isnull = false;
363
+ /* be careful to apply operator right way 'round */
364
+ if (varonleft )
365
+ fcinfo -> args [1 ].value = constval ;
366
+ else
367
+ fcinfo -> args [0 ].value = constval ;
368
+
352
369
for (i = 0 ; i < sslot .nvalues ; i ++ )
353
370
{
354
- /* be careful to apply operator right way 'round */
371
+ Datum fresult ;
372
+
355
373
if (varonleft )
356
- match = DatumGetBool (FunctionCall2Coll (& eqproc ,
357
- sslot .stacoll ,
358
- sslot .values [i ],
359
- constval ));
374
+ fcinfo -> args [0 ].value = sslot .values [i ];
360
375
else
361
- match = DatumGetBool (FunctionCall2Coll (& eqproc ,
362
- sslot .stacoll ,
363
- constval ,
364
- sslot .values [i ]));
365
- if (match )
376
+ fcinfo -> args [1 ].value = sslot .values [i ];
377
+ fcinfo -> isnull = false;
378
+ fresult = FunctionCallInvoke (fcinfo );
379
+ if (!fcinfo -> isnull && DatumGetBool (fresult ))
380
+ {
381
+ match = true;
366
382
break ;
383
+ }
367
384
}
368
385
}
369
386
else
@@ -723,17 +740,36 @@ mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
723
740
STATISTIC_KIND_MCV , InvalidOid ,
724
741
ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS ))
725
742
{
743
+ LOCAL_FCINFO (fcinfo , 2 );
744
+
745
+ /*
746
+ * We invoke the opproc "by hand" so that we won't fail on NULL
747
+ * results. Such cases won't arise for normal comparison functions,
748
+ * but generic_restriction_selectivity could perhaps be used with
749
+ * operators that can return NULL. A small side benefit is to not
750
+ * need to re-initialize the fcinfo struct from scratch each time.
751
+ */
752
+ InitFunctionCallInfoData (* fcinfo , opproc , 2 , sslot .stacoll ,
753
+ NULL , NULL );
754
+ fcinfo -> args [0 ].isnull = false;
755
+ fcinfo -> args [1 ].isnull = false;
756
+ /* be careful to apply operator right way 'round */
757
+ if (varonleft )
758
+ fcinfo -> args [1 ].value = constval ;
759
+ else
760
+ fcinfo -> args [0 ].value = constval ;
761
+
726
762
for (i = 0 ; i < sslot .nvalues ; i ++ )
727
763
{
728
- if ( varonleft ?
729
- DatumGetBool ( FunctionCall2Coll ( opproc ,
730
- sslot . stacoll ,
731
- sslot .values [i ],
732
- constval )) :
733
- DatumGetBool ( FunctionCall2Coll ( opproc ,
734
- sslot . stacoll ,
735
- constval ,
736
- sslot . values [ i ]) ))
764
+ Datum fresult ;
765
+
766
+ if ( varonleft )
767
+ fcinfo -> args [ 0 ]. value = sslot .values [i ];
768
+ else
769
+ fcinfo -> args [ 1 ]. value = sslot . values [ i ];
770
+ fcinfo -> isnull = false;
771
+ fresult = FunctionCallInvoke ( fcinfo );
772
+ if (! fcinfo -> isnull && DatumGetBool ( fresult ))
737
773
mcv_selec += sslot .numbers [i ];
738
774
sumcommon += sslot .numbers [i ];
739
775
}
@@ -798,20 +834,39 @@ histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
798
834
* hist_size = sslot .nvalues ;
799
835
if (sslot .nvalues >= min_hist_size )
800
836
{
837
+ LOCAL_FCINFO (fcinfo , 2 );
801
838
int nmatch = 0 ;
802
839
int i ;
803
840
841
+ /*
842
+ * We invoke the opproc "by hand" so that we won't fail on NULL
843
+ * results. Such cases won't arise for normal comparison
844
+ * functions, but generic_restriction_selectivity could perhaps be
845
+ * used with operators that can return NULL. A small side benefit
846
+ * is to not need to re-initialize the fcinfo struct from scratch
847
+ * each time.
848
+ */
849
+ InitFunctionCallInfoData (* fcinfo , opproc , 2 , sslot .stacoll ,
850
+ NULL , NULL );
851
+ fcinfo -> args [0 ].isnull = false;
852
+ fcinfo -> args [1 ].isnull = false;
853
+ /* be careful to apply operator right way 'round */
854
+ if (varonleft )
855
+ fcinfo -> args [1 ].value = constval ;
856
+ else
857
+ fcinfo -> args [0 ].value = constval ;
858
+
804
859
for (i = n_skip ; i < sslot .nvalues - n_skip ; i ++ )
805
860
{
806
- if ( varonleft ?
807
- DatumGetBool ( FunctionCall2Coll ( opproc ,
808
- sslot . stacoll ,
809
- sslot .values [i ],
810
- constval )) :
811
- DatumGetBool ( FunctionCall2Coll ( opproc ,
812
- sslot . stacoll ,
813
- constval ,
814
- sslot . values [ i ]) ))
861
+ Datum fresult ;
862
+
863
+ if ( varonleft )
864
+ fcinfo -> args [ 0 ]. value = sslot .values [i ];
865
+ else
866
+ fcinfo -> args [ 1 ]. value = sslot . values [ i ];
867
+ fcinfo -> isnull = false;
868
+ fresult = FunctionCallInvoke ( fcinfo );
869
+ if (! fcinfo -> isnull && DatumGetBool ( fresult ))
815
870
nmatch ++ ;
816
871
}
817
872
result = ((double ) nmatch ) / ((double ) (sslot .nvalues - 2 * n_skip ));
@@ -2292,6 +2347,7 @@ eqjoinsel_inner(Oid opfuncoid,
2292
2347
* results", Technical Report 1018, Computer Science Dept., University
2293
2348
* of Wisconsin, Madison, March 1991 (available from ftp.cs.wisc.edu).
2294
2349
*/
2350
+ LOCAL_FCINFO (fcinfo , 2 );
2295
2351
FmgrInfo eqproc ;
2296
2352
bool * hasmatch1 ;
2297
2353
bool * hasmatch2 ;
@@ -2310,6 +2366,18 @@ eqjoinsel_inner(Oid opfuncoid,
2310
2366
nmatches ;
2311
2367
2312
2368
fmgr_info (opfuncoid , & eqproc );
2369
+
2370
+ /*
2371
+ * Save a few cycles by setting up the fcinfo struct just once. Using
2372
+ * FunctionCallInvoke directly also avoids failure if the eqproc
2373
+ * returns NULL, though really equality functions should never do
2374
+ * that.
2375
+ */
2376
+ InitFunctionCallInfoData (* fcinfo , & eqproc , 2 , sslot1 -> stacoll ,
2377
+ NULL , NULL );
2378
+ fcinfo -> args [0 ].isnull = false;
2379
+ fcinfo -> args [1 ].isnull = false;
2380
+
2313
2381
hasmatch1 = (bool * ) palloc0 (sslot1 -> nvalues * sizeof (bool ));
2314
2382
hasmatch2 = (bool * ) palloc0 (sslot2 -> nvalues * sizeof (bool ));
2315
2383
@@ -2325,14 +2393,18 @@ eqjoinsel_inner(Oid opfuncoid,
2325
2393
{
2326
2394
int j ;
2327
2395
2396
+ fcinfo -> args [0 ].value = sslot1 -> values [i ];
2397
+
2328
2398
for (j = 0 ; j < sslot2 -> nvalues ; j ++ )
2329
2399
{
2400
+ Datum fresult ;
2401
+
2330
2402
if (hasmatch2 [j ])
2331
2403
continue ;
2332
- if ( DatumGetBool ( FunctionCall2Coll ( & eqproc ,
2333
- sslot1 -> stacoll ,
2334
- sslot1 -> values [ i ],
2335
- sslot2 -> values [ j ]) ))
2404
+ fcinfo -> args [ 1 ]. value = sslot2 -> values [ j ];
2405
+ fcinfo -> isnull = false;
2406
+ fresult = FunctionCallInvoke ( fcinfo );
2407
+ if (! fcinfo -> isnull && DatumGetBool ( fresult ))
2336
2408
{
2337
2409
hasmatch1 [i ] = hasmatch2 [j ] = true;
2338
2410
matchprodfreq += sslot1 -> numbers [i ] * sslot2 -> numbers [j ];
@@ -2502,6 +2574,7 @@ eqjoinsel_semi(Oid opfuncoid,
2502
2574
* lists. We still have to estimate for the remaining population, but
2503
2575
* in a skewed distribution this gives us a big leg up in accuracy.
2504
2576
*/
2577
+ LOCAL_FCINFO (fcinfo , 2 );
2505
2578
FmgrInfo eqproc ;
2506
2579
bool * hasmatch1 ;
2507
2580
bool * hasmatch2 ;
@@ -2523,6 +2596,18 @@ eqjoinsel_semi(Oid opfuncoid,
2523
2596
clamped_nvalues2 = Min (sslot2 -> nvalues , nd2 );
2524
2597
2525
2598
fmgr_info (opfuncoid , & eqproc );
2599
+
2600
+ /*
2601
+ * Save a few cycles by setting up the fcinfo struct just once. Using
2602
+ * FunctionCallInvoke directly also avoids failure if the eqproc
2603
+ * returns NULL, though really equality functions should never do
2604
+ * that.
2605
+ */
2606
+ InitFunctionCallInfoData (* fcinfo , & eqproc , 2 , sslot1 -> stacoll ,
2607
+ NULL , NULL );
2608
+ fcinfo -> args [0 ].isnull = false;
2609
+ fcinfo -> args [1 ].isnull = false;
2610
+
2526
2611
hasmatch1 = (bool * ) palloc0 (sslot1 -> nvalues * sizeof (bool ));
2527
2612
hasmatch2 = (bool * ) palloc0 (clamped_nvalues2 * sizeof (bool ));
2528
2613
@@ -2537,14 +2622,18 @@ eqjoinsel_semi(Oid opfuncoid,
2537
2622
{
2538
2623
int j ;
2539
2624
2625
+ fcinfo -> args [0 ].value = sslot1 -> values [i ];
2626
+
2540
2627
for (j = 0 ; j < clamped_nvalues2 ; j ++ )
2541
2628
{
2629
+ Datum fresult ;
2630
+
2542
2631
if (hasmatch2 [j ])
2543
2632
continue ;
2544
- if ( DatumGetBool ( FunctionCall2Coll ( & eqproc ,
2545
- sslot1 -> stacoll ,
2546
- sslot1 -> values [ i ],
2547
- sslot2 -> values [ j ]) ))
2633
+ fcinfo -> args [ 1 ]. value = sslot2 -> values [ j ];
2634
+ fcinfo -> isnull = false;
2635
+ fresult = FunctionCallInvoke ( fcinfo );
2636
+ if (! fcinfo -> isnull && DatumGetBool ( fresult ))
2548
2637
{
2549
2638
hasmatch1 [i ] = hasmatch2 [j ] = true;
2550
2639
nmatches ++ ;
@@ -3687,8 +3776,9 @@ double
3687
3776
estimate_hashagg_tablesize (Path * path , const AggClauseCosts * agg_costs ,
3688
3777
double dNumGroups )
3689
3778
{
3690
- Size hashentrysize = hash_agg_entry_size (
3691
- agg_costs -> numAggs , path -> pathtarget -> width , agg_costs -> transitionSpace );
3779
+ Size hashentrysize = hash_agg_entry_size (agg_costs -> numAggs ,
3780
+ path -> pathtarget -> width ,
3781
+ agg_costs -> transitionSpace );
3692
3782
3693
3783
/*
3694
3784
* Note that this disregards the effect of fill-factor and growth policy
0 commit comments