]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/selfuncs.c
Post-PG 10 beta1 pgindent run
[postgresql] / src / backend / utils / adt / selfuncs.c
index 9b157f4456bd08d4a2c4c4f36d00c55ad8200757..6e491bbc21ec9660dc45949455c03f1a17a70597 100644 (file)
@@ -170,7 +170,7 @@ static double eqjoinsel_semi(Oid operator,
                           VariableStatData *vardata1, VariableStatData *vardata2,
                           RelOptInfo *inner_rel);
 static bool estimate_multivariate_ndistinct(PlannerInfo *root,
-                          RelOptInfo *rel, List **varinfos, double *ndistinct);
+                                               RelOptInfo *rel, List **varinfos, double *ndistinct);
 static bool convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
                                  Datum lobound, Datum hibound, Oid boundstypid,
                                  double *scaledlobound, double *scaledhibound);
@@ -299,10 +299,7 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                                                                          (opfuncoid = get_opcode(operator))))
        {
                Form_pg_statistic stats;
-               Datum      *values;
-               int                     nvalues;
-               float4     *numbers;
-               int                     nnumbers;
+               AttStatsSlot sslot;
                bool            match = false;
                int                     i;
 
@@ -315,30 +312,27 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                 * don't like this, maybe you shouldn't be using eqsel for your
                 * operator...)
                 */
-               if (get_attstatsslot(vardata->statsTuple,
-                                                        vardata->atttype, vardata->atttypmod,
+               if (get_attstatsslot(&sslot, vardata->statsTuple,
                                                         STATISTIC_KIND_MCV, InvalidOid,
-                                                        NULL,
-                                                        &values, &nvalues,
-                                                        &numbers, &nnumbers))
+                                                        ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS))
                {
                        FmgrInfo        eqproc;
 
                        fmgr_info(opfuncoid, &eqproc);
 
-                       for (i = 0; i < nvalues; i++)
+                       for (i = 0; i < sslot.nvalues; i++)
                        {
                                /* be careful to apply operator right way 'round */
                                if (varonleft)
                                        match = DatumGetBool(FunctionCall2Coll(&eqproc,
                                                                                                           DEFAULT_COLLATION_OID,
-                                                                                                                  values[i],
+                                                                                                                  sslot.values[i],
                                                                                                                   constval));
                                else
                                        match = DatumGetBool(FunctionCall2Coll(&eqproc,
                                                                                                           DEFAULT_COLLATION_OID,
                                                                                                                   constval,
-                                                                                                                  values[i]));
+                                                                                                                  sslot.values[i]));
                                if (match)
                                        break;
                        }
@@ -346,9 +340,7 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                else
                {
                        /* no most-common-value info available */
-                       values = NULL;
-                       numbers = NULL;
-                       i = nvalues = nnumbers = 0;
+                       i = 0;                          /* keep compiler quiet */
                }
 
                if (match)
@@ -357,7 +349,7 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                         * Constant is "=" to this common value.  We know selectivity
                         * exactly (or as exactly as ANALYZE could calculate it, anyway).
                         */
-                       selec = numbers[i];
+                       selec = sslot.numbers[i];
                }
                else
                {
@@ -369,8 +361,8 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                        double          sumcommon = 0.0;
                        double          otherdistinct;
 
-                       for (i = 0; i < nnumbers; i++)
-                               sumcommon += numbers[i];
+                       for (i = 0; i < sslot.nnumbers; i++)
+                               sumcommon += sslot.numbers[i];
                        selec = 1.0 - sumcommon - stats->stanullfrac;
                        CLAMP_PROBABILITY(selec);
 
@@ -379,7 +371,8 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                         * all the not-common values share this remaining fraction
                         * equally, so we divide by the number of other distinct values.
                         */
-                       otherdistinct = get_variable_numdistinct(vardata, &isdefault) - nnumbers;
+                       otherdistinct = get_variable_numdistinct(vardata, &isdefault) -
+                               sslot.nnumbers;
                        if (otherdistinct > 1)
                                selec /= otherdistinct;
 
@@ -387,12 +380,11 @@ var_eq_const(VariableStatData *vardata, Oid operator,
                         * Another cross-check: selectivity shouldn't be estimated as more
                         * than the least common "most common value".
                         */
-                       if (nnumbers > 0 && selec > numbers[nnumbers - 1])
-                               selec = numbers[nnumbers - 1];
+                       if (sslot.nnumbers > 0 && selec > sslot.numbers[sslot.nnumbers - 1])
+                               selec = sslot.numbers[sslot.nnumbers - 1];
                }
 
-               free_attstatsslot(vardata->atttype, values, nvalues,
-                                                 numbers, nnumbers);
+               free_attstatsslot(&sslot);
        }
        else
        {
@@ -435,8 +427,7 @@ var_eq_non_const(VariableStatData *vardata, Oid operator,
        {
                Form_pg_statistic stats;
                double          ndistinct;
-               float4     *numbers;
-               int                     nnumbers;
+               AttStatsSlot sslot;
 
                stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
 
@@ -459,16 +450,13 @@ var_eq_non_const(VariableStatData *vardata, Oid operator,
                 * Cross-check: selectivity should never be estimated as more than the
                 * most common value's.
                 */
-               if (get_attstatsslot(vardata->statsTuple,
-                                                        vardata->atttype, vardata->atttypmod,
+               if (get_attstatsslot(&sslot, vardata->statsTuple,
                                                         STATISTIC_KIND_MCV, InvalidOid,
-                                                        NULL,
-                                                        NULL, NULL,
-                                                        &numbers, &nnumbers))
+                                                        ATTSTATSSLOT_NUMBERS))
                {
-                       if (nnumbers > 0 && selec > numbers[0])
-                               selec = numbers[0];
-                       free_attstatsslot(vardata->atttype, NULL, 0, numbers, nnumbers);
+                       if (sslot.nnumbers > 0 && selec > sslot.numbers[0])
+                               selec = sslot.numbers[0];
+                       free_attstatsslot(&sslot);
                }
        }
        else
@@ -620,10 +608,7 @@ mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
 {
        double          mcv_selec,
                                sumcommon;
-       Datum      *values;
-       int                     nvalues;
-       float4     *numbers;
-       int                     nnumbers;
+       AttStatsSlot sslot;
        int                     i;
 
        mcv_selec = 0.0;
@@ -631,29 +616,25 @@ mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
 
        if (HeapTupleIsValid(vardata->statsTuple) &&
                statistic_proc_security_check(vardata, opproc->fn_oid) &&
-               get_attstatsslot(vardata->statsTuple,
-                                                vardata->atttype, vardata->atttypmod,
+               get_attstatsslot(&sslot, vardata->statsTuple,
                                                 STATISTIC_KIND_MCV, InvalidOid,
-                                                NULL,
-                                                &values, &nvalues,
-                                                &numbers, &nnumbers))
+                                                ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS))
        {
-               for (i = 0; i < nvalues; i++)
+               for (i = 0; i < sslot.nvalues; i++)
                {
                        if (varonleft ?
                                DatumGetBool(FunctionCall2Coll(opproc,
                                                                                           DEFAULT_COLLATION_OID,
-                                                                                          values[i],
+                                                                                          sslot.values[i],
                                                                                           constval)) :
                                DatumGetBool(FunctionCall2Coll(opproc,
                                                                                           DEFAULT_COLLATION_OID,
                                                                                           constval,
-                                                                                          values[i])))
-                               mcv_selec += numbers[i];
-                       sumcommon += numbers[i];
+                                                                                          sslot.values[i])))
+                               mcv_selec += sslot.numbers[i];
+                       sumcommon += sslot.numbers[i];
                }
-               free_attstatsslot(vardata->atttype, values, nvalues,
-                                                 numbers, nnumbers);
+               free_attstatsslot(&sslot);
        }
 
        *sumcommonp = sumcommon;
@@ -699,8 +680,7 @@ histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
                                          int *hist_size)
 {
        double          result;
-       Datum      *values;
-       int                     nvalues;
+       AttStatsSlot sslot;
 
        /* check sanity of parameters */
        Assert(n_skip >= 0);
@@ -708,37 +688,34 @@ histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
 
        if (HeapTupleIsValid(vardata->statsTuple) &&
                statistic_proc_security_check(vardata, opproc->fn_oid) &&
-               get_attstatsslot(vardata->statsTuple,
-                                                vardata->atttype, vardata->atttypmod,
+               get_attstatsslot(&sslot, vardata->statsTuple,
                                                 STATISTIC_KIND_HISTOGRAM, InvalidOid,
-                                                NULL,
-                                                &values, &nvalues,
-                                                NULL, NULL))
+                                                ATTSTATSSLOT_VALUES))
        {
-               *hist_size = nvalues;
-               if (nvalues >= min_hist_size)
+               *hist_size = sslot.nvalues;
+               if (sslot.nvalues >= min_hist_size)
                {
                        int                     nmatch = 0;
                        int                     i;
 
-                       for (i = n_skip; i < nvalues - n_skip; i++)
+                       for (i = n_skip; i < sslot.nvalues - n_skip; i++)
                        {
                                if (varonleft ?
                                        DatumGetBool(FunctionCall2Coll(opproc,
                                                                                                   DEFAULT_COLLATION_OID,
-                                                                                                  values[i],
+                                                                                                  sslot.values[i],
                                                                                                   constval)) :
                                        DatumGetBool(FunctionCall2Coll(opproc,
                                                                                                   DEFAULT_COLLATION_OID,
                                                                                                   constval,
-                                                                                                  values[i])))
+                                                                                                  sslot.values[i])))
                                        nmatch++;
                        }
-                       result = ((double) nmatch) / ((double) (nvalues - 2 * n_skip));
+                       result = ((double) nmatch) / ((double) (sslot.nvalues - 2 * n_skip));
                }
                else
                        result = -1;
-               free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
+               free_attstatsslot(&sslot);
        }
        else
        {
@@ -768,9 +745,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                                                   Datum constval, Oid consttype)
 {
        double          hist_selec;
-       Oid                     hist_op;
-       Datum      *values;
-       int                     nvalues;
+       AttStatsSlot sslot;
 
        hist_selec = -1.0;
 
@@ -786,14 +761,11 @@ ineq_histogram_selectivity(PlannerInfo *root,
         */
        if (HeapTupleIsValid(vardata->statsTuple) &&
                statistic_proc_security_check(vardata, opproc->fn_oid) &&
-               get_attstatsslot(vardata->statsTuple,
-                                                vardata->atttype, vardata->atttypmod,
+               get_attstatsslot(&sslot, vardata->statsTuple,
                                                 STATISTIC_KIND_HISTOGRAM, InvalidOid,
-                                                &hist_op,
-                                                &values, &nvalues,
-                                                NULL, NULL))
+                                                ATTSTATSSLOT_VALUES))
        {
-               if (nvalues > 1)
+               if (sslot.nvalues > 1)
                {
                        /*
                         * Use binary search to find proper location, ie, the first slot
@@ -812,7 +784,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                         */
                        double          histfrac;
                        int                     lobound = 0;    /* first possible slot to search */
-                       int                     hibound = nvalues;              /* last+1 slot to search */
+                       int                     hibound = sslot.nvalues;                /* last+1 slot to search */
                        bool            have_end = false;
 
                        /*
@@ -821,12 +793,12 @@ ineq_histogram_selectivity(PlannerInfo *root,
                         * one of them to be updated, so we deal with that within the
                         * loop.)
                         */
-                       if (nvalues == 2)
+                       if (sslot.nvalues == 2)
                                have_end = get_actual_variable_range(root,
                                                                                                         vardata,
-                                                                                                        hist_op,
-                                                                                                        &values[0],
-                                                                                                        &values[1]);
+                                                                                                        sslot.staop,
+                                                                                                        &sslot.values[0],
+                                                                                                        &sslot.values[1]);
 
                        while (lobound < hibound)
                        {
@@ -838,22 +810,22 @@ ineq_histogram_selectivity(PlannerInfo *root,
                                 * histogram entry, first try to replace it with the actual
                                 * current min or max (unless we already did so above).
                                 */
-                               if (probe == 0 && nvalues > 2)
+                               if (probe == 0 && sslot.nvalues > 2)
                                        have_end = get_actual_variable_range(root,
                                                                                                                 vardata,
-                                                                                                                hist_op,
-                                                                                                                &values[0],
+                                                                                                                sslot.staop,
+                                                                                                                &sslot.values[0],
                                                                                                                 NULL);
-                               else if (probe == nvalues - 1 && nvalues > 2)
+                               else if (probe == sslot.nvalues - 1 && sslot.nvalues > 2)
                                        have_end = get_actual_variable_range(root,
                                                                                                                 vardata,
-                                                                                                                hist_op,
+                                                                                                                sslot.staop,
                                                                                                                 NULL,
-                                                                                                                &values[probe]);
+                                                                                                          &sslot.values[probe]);
 
                                ltcmp = DatumGetBool(FunctionCall2Coll(opproc,
                                                                                                           DEFAULT_COLLATION_OID,
-                                                                                                          values[probe],
+                                                                                                          sslot.values[probe],
                                                                                                           constval));
                                if (isgt)
                                        ltcmp = !ltcmp;
@@ -868,7 +840,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                                /* Constant is below lower histogram boundary. */
                                histfrac = 0.0;
                        }
-                       else if (lobound >= nvalues)
+                       else if (lobound >= sslot.nvalues)
                        {
                                /* Constant is above upper histogram boundary. */
                                histfrac = 1.0;
@@ -889,7 +861,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                                 * interpolation within this bin.
                                 */
                                if (convert_to_scalar(constval, consttype, &val,
-                                                                         values[i - 1], values[i],
+                                                                         sslot.values[i - 1], sslot.values[i],
                                                                          vardata->vartype,
                                                                          &low, &high))
                                {
@@ -936,7 +908,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                                 * binfrac partial bin below the constant.
                                 */
                                histfrac = (double) (i - 1) + binfrac;
-                               histfrac /= (double) (nvalues - 1);
+                               histfrac /= (double) (sslot.nvalues - 1);
                        }
 
                        /*
@@ -964,7 +936,7 @@ ineq_histogram_selectivity(PlannerInfo *root,
                        }
                }
 
-               free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
+               free_attstatsslot(&sslot);
        }
 
        return hist_selec;
@@ -1517,21 +1489,15 @@ booltestsel(PlannerInfo *root, BoolTestType booltesttype, Node *arg,
        {
                Form_pg_statistic stats;
                double          freq_null;
-               Datum      *values;
-               int                     nvalues;
-               float4     *numbers;
-               int                     nnumbers;
+               AttStatsSlot sslot;
 
                stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple);
                freq_null = stats->stanullfrac;
 
-               if (get_attstatsslot(vardata.statsTuple,
-                                                        vardata.atttype, vardata.atttypmod,
+               if (get_attstatsslot(&sslot, vardata.statsTuple,
                                                         STATISTIC_KIND_MCV, InvalidOid,
-                                                        NULL,
-                                                        &values, &nvalues,
-                                                        &numbers, &nnumbers)
-                       && nnumbers > 0)
+                                                        ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS)
+                       && sslot.nnumbers > 0)
                {
                        double          freq_true;
                        double          freq_false;
@@ -1539,10 +1505,10 @@ booltestsel(PlannerInfo *root, BoolTestType booltesttype, Node *arg,
                        /*
                         * Get first MCV frequency and derive frequency for true.
                         */
-                       if (DatumGetBool(values[0]))
-                               freq_true = numbers[0];
+                       if (DatumGetBool(sslot.values[0]))
+                               freq_true = sslot.numbers[0];
                        else
-                               freq_true = 1.0 - numbers[0] - freq_null;
+                               freq_true = 1.0 - sslot.numbers[0] - freq_null;
 
                        /*
                         * Next derive frequency for false. Then use these as appropriate
@@ -1583,8 +1549,7 @@ booltestsel(PlannerInfo *root, BoolTestType booltesttype, Node *arg,
                                        break;
                        }
 
-                       free_attstatsslot(vardata.atttype, values, nvalues,
-                                                         numbers, nnumbers);
+                       free_attstatsslot(&sslot);
                }
                else
                {
@@ -2274,34 +2239,26 @@ eqjoinsel_inner(Oid operator,
        Form_pg_statistic stats1 = NULL;
        Form_pg_statistic stats2 = NULL;
        bool            have_mcvs1 = false;
-       Datum      *values1 = NULL;
-       int                     nvalues1 = 0;
-       float4     *numbers1 = NULL;
-       int                     nnumbers1 = 0;
        bool            have_mcvs2 = false;
-       Datum      *values2 = NULL;
-       int                     nvalues2 = 0;
-       float4     *numbers2 = NULL;
-       int                     nnumbers2 = 0;
+       AttStatsSlot sslot1;
+       AttStatsSlot sslot2;
 
        nd1 = get_variable_numdistinct(vardata1, &isdefault1);
        nd2 = get_variable_numdistinct(vardata2, &isdefault2);
 
        opfuncoid = get_opcode(operator);
 
+       memset(&sslot1, 0, sizeof(sslot1));
+       memset(&sslot2, 0, sizeof(sslot2));
+
        if (HeapTupleIsValid(vardata1->statsTuple))
        {
                /* note we allow use of nullfrac regardless of security check */
                stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
                if (statistic_proc_security_check(vardata1, opfuncoid))
-                       have_mcvs1 = get_attstatsslot(vardata1->statsTuple,
-                                                                                 vardata1->atttype,
-                                                                                 vardata1->atttypmod,
-                                                                                 STATISTIC_KIND_MCV,
-                                                                                 InvalidOid,
-                                                                                 NULL,
-                                                                                 &values1, &nvalues1,
-                                                                                 &numbers1, &nnumbers1);
+                       have_mcvs1 = get_attstatsslot(&sslot1, vardata1->statsTuple,
+                                                                                 STATISTIC_KIND_MCV, InvalidOid,
+                                                                ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS);
        }
 
        if (HeapTupleIsValid(vardata2->statsTuple))
@@ -2309,14 +2266,9 @@ eqjoinsel_inner(Oid operator,
                /* note we allow use of nullfrac regardless of security check */
                stats2 = (Form_pg_statistic) GETSTRUCT(vardata2->statsTuple);
                if (statistic_proc_security_check(vardata2, opfuncoid))
-                       have_mcvs2 = get_attstatsslot(vardata2->statsTuple,
-                                                                                 vardata2->atttype,
-                                                                                 vardata2->atttypmod,
-                                                                                 STATISTIC_KIND_MCV,
-                                                                                 InvalidOid,
-                                                                                 NULL,
-                                                                                 &values2, &nvalues2,
-                                                                                 &numbers2, &nnumbers2);
+                       have_mcvs2 = get_attstatsslot(&sslot2, vardata2->statsTuple,
+                                                                                 STATISTIC_KIND_MCV, InvalidOid,
+                                                                ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS);
        }
 
        if (have_mcvs1 && have_mcvs2)
@@ -2351,8 +2303,8 @@ eqjoinsel_inner(Oid operator,
                                        nmatches;
 
                fmgr_info(opfuncoid, &eqproc);
-               hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool));
-               hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool));
+               hasmatch1 = (bool *) palloc0(sslot1.nvalues * sizeof(bool));
+               hasmatch2 = (bool *) palloc0(sslot2.nvalues * sizeof(bool));
 
                /*
                 * Note we assume that each MCV will match at most one member of the
@@ -2362,21 +2314,21 @@ eqjoinsel_inner(Oid operator,
                 */
                matchprodfreq = 0.0;
                nmatches = 0;
-               for (i = 0; i < nvalues1; i++)
+               for (i = 0; i < sslot1.nvalues; i++)
                {
                        int                     j;
 
-                       for (j = 0; j < nvalues2; j++)
+                       for (j = 0; j < sslot2.nvalues; j++)
                        {
                                if (hasmatch2[j])
                                        continue;
                                if (DatumGetBool(FunctionCall2Coll(&eqproc,
                                                                                                   DEFAULT_COLLATION_OID,
-                                                                                                  values1[i],
-                                                                                                  values2[j])))
+                                                                                                  sslot1.values[i],
+                                                                                                  sslot2.values[j])))
                                {
                                        hasmatch1[i] = hasmatch2[j] = true;
-                                       matchprodfreq += numbers1[i] * numbers2[j];
+                                       matchprodfreq += sslot1.numbers[i] * sslot2.numbers[j];
                                        nmatches++;
                                        break;
                                }
@@ -2385,22 +2337,22 @@ eqjoinsel_inner(Oid operator,
                CLAMP_PROBABILITY(matchprodfreq);
                /* Sum up frequencies of matched and unmatched MCVs */
                matchfreq1 = unmatchfreq1 = 0.0;
-               for (i = 0; i < nvalues1; i++)
+               for (i = 0; i < sslot1.nvalues; i++)
                {
                        if (hasmatch1[i])
-                               matchfreq1 += numbers1[i];
+                               matchfreq1 += sslot1.numbers[i];
                        else
-                               unmatchfreq1 += numbers1[i];
+                               unmatchfreq1 += sslot1.numbers[i];
                }
                CLAMP_PROBABILITY(matchfreq1);
                CLAMP_PROBABILITY(unmatchfreq1);
                matchfreq2 = unmatchfreq2 = 0.0;
-               for (i = 0; i < nvalues2; i++)
+               for (i = 0; i < sslot2.nvalues; i++)
                {
                        if (hasmatch2[i])
-                               matchfreq2 += numbers2[i];
+                               matchfreq2 += sslot2.numbers[i];
                        else
-                               unmatchfreq2 += numbers2[i];
+                               unmatchfreq2 += sslot2.numbers[i];
                }
                CLAMP_PROBABILITY(matchfreq2);
                CLAMP_PROBABILITY(unmatchfreq2);
@@ -2425,15 +2377,15 @@ eqjoinsel_inner(Oid operator,
                 * MCVs plus non-MCV values.
                 */
                totalsel1 = matchprodfreq;
-               if (nd2 > nvalues2)
-                       totalsel1 += unmatchfreq1 * otherfreq2 / (nd2 - nvalues2);
+               if (nd2 > sslot2.nvalues)
+                       totalsel1 += unmatchfreq1 * otherfreq2 / (nd2 - sslot2.nvalues);
                if (nd2 > nmatches)
                        totalsel1 += otherfreq1 * (otherfreq2 + unmatchfreq2) /
                                (nd2 - nmatches);
                /* Same estimate from the point of view of relation 2. */
                totalsel2 = matchprodfreq;
-               if (nd1 > nvalues1)
-                       totalsel2 += unmatchfreq2 * otherfreq1 / (nd1 - nvalues1);
+               if (nd1 > sslot1.nvalues)
+                       totalsel2 += unmatchfreq2 * otherfreq1 / (nd1 - sslot1.nvalues);
                if (nd1 > nmatches)
                        totalsel2 += otherfreq2 * (otherfreq1 + unmatchfreq1) /
                                (nd1 - nmatches);
@@ -2478,12 +2430,8 @@ eqjoinsel_inner(Oid operator,
                        selec /= nd2;
        }
 
-       if (have_mcvs1)
-               free_attstatsslot(vardata1->atttype, values1, nvalues1,
-                                                 numbers1, nnumbers1);
-       if (have_mcvs2)
-               free_attstatsslot(vardata2->atttype, values2, nvalues2,
-                                                 numbers2, nnumbers2);
+       free_attstatsslot(&sslot1);
+       free_attstatsslot(&sslot2);
 
        return selec;
 }
@@ -2508,21 +2456,18 @@ eqjoinsel_semi(Oid operator,
        Oid                     opfuncoid;
        Form_pg_statistic stats1 = NULL;
        bool            have_mcvs1 = false;
-       Datum      *values1 = NULL;
-       int                     nvalues1 = 0;
-       float4     *numbers1 = NULL;
-       int                     nnumbers1 = 0;
        bool            have_mcvs2 = false;
-       Datum      *values2 = NULL;
-       int                     nvalues2 = 0;
-       float4     *numbers2 = NULL;
-       int                     nnumbers2 = 0;
+       AttStatsSlot sslot1;
+       AttStatsSlot sslot2;
 
        nd1 = get_variable_numdistinct(vardata1, &isdefault1);
        nd2 = get_variable_numdistinct(vardata2, &isdefault2);
 
        opfuncoid = OidIsValid(operator) ? get_opcode(operator) : InvalidOid;
 
+       memset(&sslot1, 0, sizeof(sslot1));
+       memset(&sslot2, 0, sizeof(sslot2));
+
        /*
         * We clamp nd2 to be not more than what we estimate the inner relation's
         * size to be.  This is intuitively somewhat reasonable since obviously
@@ -2561,27 +2506,18 @@ eqjoinsel_semi(Oid operator,
                /* note we allow use of nullfrac regardless of security check */
                stats1 = (Form_pg_statistic) GETSTRUCT(vardata1->statsTuple);
                if (statistic_proc_security_check(vardata1, opfuncoid))
-                       have_mcvs1 = get_attstatsslot(vardata1->statsTuple,
-                                                                                 vardata1->atttype,
-                                                                                 vardata1->atttypmod,
-                                                                                 STATISTIC_KIND_MCV,
-                                                                                 InvalidOid,
-                                                                                 NULL,
-                                                                                 &values1, &nvalues1,
-                                                                                 &numbers1, &nnumbers1);
+                       have_mcvs1 = get_attstatsslot(&sslot1, vardata1->statsTuple,
+                                                                                 STATISTIC_KIND_MCV, InvalidOid,
+                                                                ATTSTATSSLOT_VALUES | ATTSTATSSLOT_NUMBERS);
        }
 
        if (HeapTupleIsValid(vardata2->statsTuple) &&
                statistic_proc_security_check(vardata2, opfuncoid))
        {
-               have_mcvs2 = get_attstatsslot(vardata2->statsTuple,
-                                                                         vardata2->atttype,
-                                                                         vardata2->atttypmod,
-                                                                         STATISTIC_KIND_MCV,
-                                                                         InvalidOid,
-                                                                         NULL,
-                                                                         &values2, &nvalues2,
-                                                                         &numbers2, &nnumbers2);
+               have_mcvs2 = get_attstatsslot(&sslot2, vardata2->statsTuple,
+                                                                         STATISTIC_KIND_MCV, InvalidOid,
+                                                                         ATTSTATSSLOT_VALUES);
+               /* note: currently don't need stanumbers from RHS */
        }
 
        if (have_mcvs1 && have_mcvs2 && OidIsValid(operator))
@@ -2607,15 +2543,15 @@ eqjoinsel_semi(Oid operator,
 
                /*
                 * The clamping above could have resulted in nd2 being less than
-                * nvalues2; in which case, we assume that precisely the nd2 most
-                * common values in the relation will appear in the join input, and so
-                * compare to only the first nd2 members of the MCV list.  Of course
-                * this is frequently wrong, but it's the best bet we can make.
+                * sslot2.nvalues; in which case, we assume that precisely the nd2
+                * most common values in the relation will appear in the join input,
+                * and so compare to only the first nd2 members of the MCV list.  Of
+                * course this is frequently wrong, but it's the best bet we can make.
                 */
-               clamped_nvalues2 = Min(nvalues2, nd2);
+               clamped_nvalues2 = Min(sslot2.nvalues, nd2);
 
                fmgr_info(opfuncoid, &eqproc);
-               hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool));
+               hasmatch1 = (bool *) palloc0(sslot1.nvalues * sizeof(bool));
                hasmatch2 = (bool *) palloc0(clamped_nvalues2 * sizeof(bool));
 
                /*
@@ -2625,7 +2561,7 @@ eqjoinsel_semi(Oid operator,
                 * and because the math wouldn't add up...
                 */
                nmatches = 0;
-               for (i = 0; i < nvalues1; i++)
+               for (i = 0; i < sslot1.nvalues; i++)
                {
                        int                     j;
 
@@ -2635,8 +2571,8 @@ eqjoinsel_semi(Oid operator,
                                        continue;
                                if (DatumGetBool(FunctionCall2Coll(&eqproc,
                                                                                                   DEFAULT_COLLATION_OID,
-                                                                                                  values1[i],
-                                                                                                  values2[j])))
+                                                                                                  sslot1.values[i],
+                                                                                                  sslot2.values[j])))
                                {
                                        hasmatch1[i] = hasmatch2[j] = true;
                                        nmatches++;
@@ -2646,10 +2582,10 @@ eqjoinsel_semi(Oid operator,
                }
                /* Sum up frequencies of matched MCVs */
                matchfreq1 = 0.0;
-               for (i = 0; i < nvalues1; i++)
+               for (i = 0; i < sslot1.nvalues; i++)
                {
                        if (hasmatch1[i])
-                               matchfreq1 += numbers1[i];
+                               matchfreq1 += sslot1.numbers[i];
                }
                CLAMP_PROBABILITY(matchfreq1);
                pfree(hasmatch1);
@@ -2704,12 +2640,8 @@ eqjoinsel_semi(Oid operator,
                        selec = 0.5 * (1.0 - nullfrac1);
        }
 
-       if (have_mcvs1)
-               free_attstatsslot(vardata1->atttype, values1, nvalues1,
-                                                 numbers1, nnumbers1);
-       if (have_mcvs2)
-               free_attstatsslot(vardata2->atttype, values2, nvalues2,
-                                                 numbers2, nnumbers2);
+       free_attstatsslot(&sslot1);
+       free_attstatsslot(&sslot2);
 
        return selec;
 }
@@ -3432,8 +3364,8 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows,
                List       *relvarinfos = NIL;
 
                /*
-                * Split the list of varinfos in two - one for the current rel,
-                * one for remaining Vars on other rels.
+                * Split the list of varinfos in two - one for the current rel, one
+                * for remaining Vars on other rels.
                 */
                relvarinfos = lcons(varinfo1, relvarinfos);
                for_each_cell(l, lnext(list_head(varinfos)))
@@ -3456,9 +3388,9 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows,
                 * Get the numdistinct estimate for the Vars of this rel.  We
                 * iteratively search for multivariate n-distinct with maximum number
                 * of vars; assuming that each var group is independent of the others,
-                * we multiply them together.  Any remaining relvarinfos after
-                * no more multivariate matches are found are assumed independent too,
-                * so their individual ndistinct estimates are multiplied also.
+                * we multiply them together.  Any remaining relvarinfos after no more
+                * multivariate matches are found are assumed independent too, so
+                * their individual ndistinct estimates are multiplied also.
                 *
                 * While iterating, count how many separate numdistinct values we
                 * apply.  We apply a fudge factor below, but only if we multiplied
@@ -3478,7 +3410,7 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows,
                        }
                        else
                        {
-                               foreach (l, relvarinfos)
+                               foreach(l, relvarinfos)
                                {
                                        GroupVarInfo *varinfo2 = (GroupVarInfo *) lfirst(l);
 
@@ -3629,8 +3561,7 @@ estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey, double nbuckets)
                                mcvfreq,
                                avgfreq;
        bool            isdefault;
-       float4     *numbers;
-       int                     nnumbers;
+       AttStatsSlot sslot;
 
        examine_variable(root, hashkey, 0, &vardata);
 
@@ -3689,20 +3620,16 @@ estimate_hash_bucketsize(PlannerInfo *root, Node *hashkey, double nbuckets)
 
        if (HeapTupleIsValid(vardata.statsTuple))
        {
-               if (get_attstatsslot(vardata.statsTuple,
-                                                        vardata.atttype, vardata.atttypmod,
+               if (get_attstatsslot(&sslot, vardata.statsTuple,
                                                         STATISTIC_KIND_MCV, InvalidOid,
-                                                        NULL,
-                                                        NULL, NULL,
-                                                        &numbers, &nnumbers))
+                                                        ATTSTATSSLOT_NUMBERS))
                {
                        /*
                         * The first MCV stat is for the most common value.
                         */
-                       if (nnumbers > 0)
-                               mcvfreq = numbers[0];
-                       free_attstatsslot(vardata.atttype, NULL, 0,
-                                                         numbers, nnumbers);
+                       if (sslot.nnumbers > 0)
+                               mcvfreq = sslot.numbers[0];
+                       free_attstatsslot(&sslot);
                }
        }
 
@@ -3775,30 +3702,32 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
        }
 
        /* look for the ndistinct statistics matching the most vars */
-       nmatches = 1; /* we require at least two matches */
+       nmatches = 1;                           /* we require at least two matches */
        foreach(lc, rel->statlist)
        {
                StatisticExtInfo *info = (StatisticExtInfo *) lfirst(lc);
                Bitmapset  *shared;
+               int                     nshared;
 
                /* skip statistics of other kinds */
                if (info->kind != STATS_EXT_NDISTINCT)
                        continue;
 
-               /* compute attnums shared by the vars and the statistic */
+               /* compute attnums shared by the vars and the statistics object */
                shared = bms_intersect(info->keys, attnums);
+               nshared = bms_num_members(shared);
 
                /*
-                * Does this statistics matches more columns than the currently
-                * best statistic?  If so, use this one instead.
+                * Does this statistics object match more columns than the currently
+                * best object?  If so, use this one instead.
                 *
-                * XXX This should break ties using name of the statistic, or
-                * something like that, to make the outcome stable.
+                * XXX This should break ties using name of the object, or something
+                * like that, to make the outcome stable.
                 */
-               if (bms_num_members(shared) > nmatches)
+               if (nshared > nmatches)
                {
                        statOid = info->statOid;
-                       nmatches = bms_num_members(shared);
+                       nmatches = nshared;
                        matched = shared;
                }
        }
@@ -3816,8 +3745,8 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
         */
        if (stats)
        {
-               int             i;
-               List   *newlist = NIL;
+               int                     i;
+               List       *newlist = NIL;
                MVNDistinctItem *item = NULL;
 
                /* Find the specific item that exactly matches the combination */
@@ -4572,7 +4501,7 @@ get_join_variables(PlannerInfo *root, List *args, SpecialJoinInfo *sjinfo,
  *     freefunc: pointer to a function to release statsTuple with.
  *     vartype: exposed type of the expression; this should always match
  *             the declared input type of the operator we are estimating for.
- *     atttype, atttypmod: type data to pass to get_attstatsslot().  This is
+ *     atttype, atttypmod: actual type/typmod of the "var" expression.  This is
  *             commonly the same as the exposed type of the variable argument,
  *             but can be different in binary-compatible-type cases.
  *     isunique: TRUE if we were able to match the var to a unique index or a
@@ -5125,8 +5054,7 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
        int16           typLen;
        bool            typByVal;
        Oid                     opfuncoid;
-       Datum      *values;
-       int                     nvalues;
+       AttStatsSlot sslot;
        int                     i;
 
        /*
@@ -5167,29 +5095,23 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
         * the one we want, fail --- this suggests that there is data we can't
         * use.
         */
-       if (get_attstatsslot(vardata->statsTuple,
-                                                vardata->atttype, vardata->atttypmod,
+       if (get_attstatsslot(&sslot, vardata->statsTuple,
                                                 STATISTIC_KIND_HISTOGRAM, sortop,
-                                                NULL,
-                                                &values, &nvalues,
-                                                NULL, NULL))
+                                                ATTSTATSSLOT_VALUES))
        {
-               if (nvalues > 0)
+               if (sslot.nvalues > 0)
                {
-                       tmin = datumCopy(values[0], typByVal, typLen);
-                       tmax = datumCopy(values[nvalues - 1], typByVal, typLen);
+                       tmin = datumCopy(sslot.values[0], typByVal, typLen);
+                       tmax = datumCopy(sslot.values[sslot.nvalues - 1], typByVal, typLen);
                        have_data = true;
                }
-               free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
+               free_attstatsslot(&sslot);
        }
-       else if (get_attstatsslot(vardata->statsTuple,
-                                                         vardata->atttype, vardata->atttypmod,
+       else if (get_attstatsslot(&sslot, vardata->statsTuple,
                                                          STATISTIC_KIND_HISTOGRAM, InvalidOid,
-                                                         NULL,
-                                                         &values, &nvalues,
-                                                         NULL, NULL))
+                                                         0))
        {
-               free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
+               free_attstatsslot(&sslot);
                return false;
        }
 
@@ -5199,12 +5121,9 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
         * the MCVs.  However, usually the MCVs will not be the extreme values, so
         * avoid unnecessary data copying.
         */
-       if (get_attstatsslot(vardata->statsTuple,
-                                                vardata->atttype, vardata->atttypmod,
+       if (get_attstatsslot(&sslot, vardata->statsTuple,
                                                 STATISTIC_KIND_MCV, InvalidOid,
-                                                NULL,
-                                                &values, &nvalues,
-                                                NULL, NULL))
+                                                ATTSTATSSLOT_VALUES))
        {
                bool            tmin_is_mcv = false;
                bool            tmax_is_mcv = false;
@@ -5212,26 +5131,26 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
 
                fmgr_info(opfuncoid, &opproc);
 
-               for (i = 0; i < nvalues; i++)
+               for (i = 0; i < sslot.nvalues; i++)
                {
                        if (!have_data)
                        {
-                               tmin = tmax = values[i];
+                               tmin = tmax = sslot.values[i];
                                tmin_is_mcv = tmax_is_mcv = have_data = true;
                                continue;
                        }
                        if (DatumGetBool(FunctionCall2Coll(&opproc,
                                                                                           DEFAULT_COLLATION_OID,
-                                                                                          values[i], tmin)))
+                                                                                          sslot.values[i], tmin)))
                        {
-                               tmin = values[i];
+                               tmin = sslot.values[i];
                                tmin_is_mcv = true;
                        }
                        if (DatumGetBool(FunctionCall2Coll(&opproc,
                                                                                           DEFAULT_COLLATION_OID,
-                                                                                          tmax, values[i])))
+                                                                                          tmax, sslot.values[i])))
                        {
-                               tmax = values[i];
+                               tmax = sslot.values[i];
                                tmax_is_mcv = true;
                        }
                }
@@ -5239,7 +5158,7 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
                        tmin = datumCopy(tmin, typByVal, typLen);
                if (tmax_is_mcv)
                        tmax = datumCopy(tmax, typByVal, typLen);
-               free_attstatsslot(vardata->atttype, values, nvalues, NULL, 0);
+               free_attstatsslot(&sslot);
        }
 
        *min = tmin;
@@ -6979,25 +6898,21 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        if (HeapTupleIsValid(vardata.statsTuple))
        {
                Oid                     sortop;
-               float4     *numbers;
-               int                     nnumbers;
+               AttStatsSlot sslot;
 
                sortop = get_opfamily_member(index->opfamily[0],
                                                                         index->opcintype[0],
                                                                         index->opcintype[0],
                                                                         BTLessStrategyNumber);
                if (OidIsValid(sortop) &&
-                       get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
-                                                        STATISTIC_KIND_CORRELATION,
-                                                        sortop,
-                                                        NULL,
-                                                        NULL, NULL,
-                                                        &numbers, &nnumbers))
+                       get_attstatsslot(&sslot, vardata.statsTuple,
+                                                        STATISTIC_KIND_CORRELATION, sortop,
+                                                        ATTSTATSSLOT_NUMBERS))
                {
                        double          varCorrelation;
 
-                       Assert(nnumbers == 1);
-                       varCorrelation = numbers[0];
+                       Assert(sslot.nnumbers == 1);
+                       varCorrelation = sslot.numbers[0];
 
                        if (index->reverse_sort[0])
                                varCorrelation = -varCorrelation;
@@ -7007,7 +6922,7 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                        else
                                costs.indexCorrelation = varCorrelation;
 
-                       free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
+                       free_attstatsslot(&sslot);
                }
        }
 
@@ -7851,8 +7766,8 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
         *
         * Because we can use all index quals equally when scanning, we can use
         * the largest correlation (in absolute value) among columns used by the
-        * query.  Start at zero, the worst possible case.  If we cannot find
-        * any correlation statistics, we will keep it as 0.
+        * query.  Start at zero, the worst possible case.  If we cannot find any
+        * correlation statistics, we will keep it as 0.
         */
        *indexCorrelation = 0;
 
@@ -7875,7 +7790,7 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                                 */
                                if (HeapTupleIsValid(vardata.statsTuple) && !vardata.freefunc)
                                        elog(ERROR,
-                                                "no function provided to release variable stats with");
+                                         "no function provided to release variable stats with");
                        }
                        else
                        {
@@ -7898,11 +7813,11 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                        attnum = qinfo->indexcol + 1;
 
                        if (get_index_stats_hook &&
-                               (*get_index_stats_hook) (root, index->indexoid, attnum, &vardata))
+                       (*get_index_stats_hook) (root, index->indexoid, attnum, &vardata))
                        {
                                /*
-                                * The hook took control of acquiring a stats tuple.  If it did
-                                * supply a tuple, it'd better have supplied a freefunc.
+                                * The hook took control of acquiring a stats tuple.  If it
+                                * did supply a tuple, it'd better have supplied a freefunc.
                                 */
                                if (HeapTupleIsValid(vardata.statsTuple) &&
                                        !vardata.freefunc)
@@ -7911,7 +7826,7 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
                        else
                        {
                                vardata.statsTuple = SearchSysCache3(STATRELATTINH,
-                                                                                                        ObjectIdGetDatum(index->indexoid),
+                                                                                  ObjectIdGetDatum(index->indexoid),
                                                                                                         Int16GetDatum(attnum),
                                                                                                         BoolGetDatum(false));
                                vardata.freefunc = ReleaseSysCache;
@@ -7920,25 +7835,21 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
 
                if (HeapTupleIsValid(vardata.statsTuple))
                {
-                       float4     *numbers;
-                       int                     nnumbers;
-
-                       if (get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
-                                                                STATISTIC_KIND_CORRELATION,
-                                                                InvalidOid,
-                                                                NULL,
-                                                                NULL, NULL,
-                                                                &numbers, &nnumbers))
+                       AttStatsSlot sslot;
+
+                       if (get_attstatsslot(&sslot, vardata.statsTuple,
+                                                                STATISTIC_KIND_CORRELATION, InvalidOid,
+                                                                ATTSTATSSLOT_NUMBERS))
                        {
                                double          varCorrelation = 0.0;
 
-                               if (nnumbers > 0)
-                                       varCorrelation = Abs(numbers[0]);
+                               if (sslot.nnumbers > 0)
+                                       varCorrelation = Abs(sslot.numbers[0]);
 
                                if (varCorrelation > *indexCorrelation)
                                        *indexCorrelation = varCorrelation;
 
-                               free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
+                               free_attstatsslot(&sslot);
                        }
                }
 
@@ -7961,8 +7872,8 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
 
        /*
         * Now estimate the number of ranges that we'll touch by using the
-        * indexCorrelation from the stats. Careful not to divide by zero
-        * (note we're using the absolute value of the correlation).
+        * indexCorrelation from the stats. Careful not to divide by zero (note
+        * we're using the absolute value of the correlation).
         */
        if (*indexCorrelation < 1.0e-10)
                estimatedRanges = indexRanges;
@@ -7977,8 +7888,8 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
        *indexSelectivity = selec;
 
        /*
-        * Compute the index qual costs, much as in genericcostestimate, to add
-        * to the index costs.
+        * Compute the index qual costs, much as in genericcostestimate, to add to
+        * the index costs.
         */
        qual_arg_cost = other_operands_eval_cost(root, qinfos) +
                orderby_operands_eval_cost(root, path);