Other arguments are the names and values of statistics corresponding
to columns in <link linkend="view-pg-stats-ext"><structname>pg_stats_ext</structname>
</link>.
- This function currently supports <literal>n_distinct</literal> and
- <literal>dependencies</literal>.
+ This function currently supports <literal>n_distinct</literal>,
+ <literal>dependencies</literal>, <literal>most_common_vals</literal>,
+ <literal>most_common_freqs</literal>,
+ and <literal>most_common_base_freqs</literal>.
</para>
<para>
Additionally, this function accepts argument name
INHERITED_ARG,
NDISTINCT_ARG,
DEPENDENCIES_ARG,
+ MOST_COMMON_VALS_ARG,
+ MOST_COMMON_FREQS_ARG,
+ MOST_COMMON_BASE_FREQS_ARG,
NUM_EXTENDED_STATS_ARGS,
};
[INHERITED_ARG] = {"inherited", BOOLOID},
[NDISTINCT_ARG] = {"n_distinct", PG_NDISTINCTOID},
[DEPENDENCIES_ARG] = {"dependencies", PG_DEPENDENCIESOID},
+ [MOST_COMMON_VALS_ARG] = {"most_common_vals", TEXTARRAYOID},
+ [MOST_COMMON_FREQS_ARG] = {"most_common_freqs", FLOAT8ARRAYOID},
+ [MOST_COMMON_BASE_FREQS_ARG] = {"most_common_base_freqs", FLOAT8ARRAYOID},
[NUM_EXTENDED_STATS_ARGS] = {0},
};
const bool *nulls,
const bool *replaces);
+static bool check_mcvlist_array(const ArrayType *arr, int argindex,
+ int required_ndims, int mcv_length);
+static Datum import_mcv(const ArrayType *mcv_arr,
+ const ArrayType *freqs_arr,
+ const ArrayType *base_freqs_arr,
+ Oid *atttypids, int32 *atttypmods,
+ Oid *atttypcolls, int numattrs,
+ bool *ok);
+
+
/*
* Fetch a pg_statistic_ext row by name and namespace OID.
*/
bool success = true;
Datum exprdatum;
bool isnull;
+ List *exprs = NIL;
+ int numattnums = 0;
int numexprs = 0;
+ int numattrs = 0;
/* arrays of type info, if we need them */
+ Oid *atttypids = NULL;
+ int32 *atttypmods = NULL;
+ Oid *atttypcolls = NULL;
Oid relid;
Oid locked_table = InvalidOid;
/*
* Fill out the StakindFlags "has" structure based on which parameters
* were provided to the function.
+ *
+ * The MCV stats composite value is an array of record type, but this is
+ * externally represented as three arrays that must be interleaved into
+ * the array of records (pg_stats_ext stores four arrays,
+ * most_common_val_nulls is built from the contents of most_common_vals).
+ * Therefore, none of the three array values is meaningful unless the
+ * other two are also present and in sync in terms of array length.
*/
+ has.mcv = (!PG_ARGISNULL(MOST_COMMON_VALS_ARG) &&
+ !PG_ARGISNULL(MOST_COMMON_FREQS_ARG) &&
+ !PG_ARGISNULL(MOST_COMMON_BASE_FREQS_ARG));
has.ndistinct = !PG_ARGISNULL(NDISTINCT_ARG);
has.dependencies = !PG_ARGISNULL(DEPENDENCIES_ARG);
/* Find out what extended statistics kinds we should expect. */
expand_stxkind(tup, &enabled);
+ numattnums = stxform->stxkeys.dim1;
/* decode expression (if any) */
exprdatum = SysCacheGetAttr(STATEXTOID,
if (!isnull)
{
char *s;
- List *exprs;
s = TextDatumGetCString(exprdatum);
exprs = (List *) stringToNode(s);
numexprs = list_length(exprs);
}
+ numattrs = numattnums + numexprs;
+
/*
* If the object cannot support ndistinct, we should not have data for it.
*/
success = false;
}
+ /*
+ * If the object cannot hold an MCV value, but any of the MCV parameters
+ * are set, then issue a WARNING and ensure that we do not try to load MCV
+ * stats later. In pg_stats_ext, most_common_val_nulls, most_common_freqs
+ * and most_common_base_freqs are NULL if most_common_vals is NULL.
+ */
+ if (!enabled.mcv)
+ {
+ if (!PG_ARGISNULL(MOST_COMMON_VALS_ARG) ||
+ !PG_ARGISNULL(MOST_COMMON_FREQS_ARG) ||
+ !PG_ARGISNULL(MOST_COMMON_BASE_FREQS_ARG))
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot specify parameters \"%s\", \"%s\" or \"%s\"",
+ extarginfo[MOST_COMMON_VALS_ARG].argname,
+ extarginfo[MOST_COMMON_FREQS_ARG].argname,
+ extarginfo[MOST_COMMON_BASE_FREQS_ARG].argname),
+ errhint("Extended statistics object \"%s\".\"%s\" does not support statistics of this type.",
+ quote_identifier(nspname),
+ quote_identifier(stxname)));
+
+ has.mcv = false;
+ success = false;
+ }
+ }
+ else if (!has.mcv)
+ {
+ /*
+ * If we do not have all of the MCV arrays set while the extended
+ * statistics object expects something, something is wrong. This
+ * issues a WARNING if a partial input has been provided.
+ */
+ if (!PG_ARGISNULL(MOST_COMMON_VALS_ARG) ||
+ !PG_ARGISNULL(MOST_COMMON_FREQS_ARG) ||
+ !PG_ARGISNULL(MOST_COMMON_BASE_FREQS_ARG))
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not use \"%s\", \"%s\" and \"%s\": missing one or more parameters",
+ extarginfo[MOST_COMMON_VALS_ARG].argname,
+ extarginfo[MOST_COMMON_FREQS_ARG].argname,
+ extarginfo[MOST_COMMON_BASE_FREQS_ARG].argname));
+ success = false;
+ }
+ }
+
+ /*
+ * Either of these statistic types requires that we supply a semi-filled
+ * VacAttrStatP array.
+ *
+ * It is not possible to use the existing lookup_var_attr_stats() and
+ * examine_attribute() because these functions will skip attributes where
+ * attstattarget is 0, and we may have statistics data to import for those
+ * attributes.
+ */
+ if (has.mcv)
+ {
+ atttypids = palloc0_array(Oid, numattrs);
+ atttypmods = palloc0_array(int32, numattrs);
+ atttypcolls = palloc0_array(Oid, numattrs);
+
+ /*
+ * The leading stxkeys are attribute numbers up through numattnums.
+ * These keys must be in ascending AttNumber order, but we do not rely
+ * on that.
+ */
+ for (int i = 0; i < numattnums; i++)
+ {
+ AttrNumber attnum = stxform->stxkeys.values[i];
+ HeapTuple atup = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
+
+ Form_pg_attribute attr;
+
+ /* Attribute not found */
+ if (!HeapTupleIsValid(atup))
+ elog(ERROR, "stxkeys references nonexistent attnum %d", attnum);
+
+ attr = (Form_pg_attribute) GETSTRUCT(atup);
+
+ if (attr->attisdropped)
+ elog(ERROR, "stxkeys references dropped attnum %d", attnum);
+
+ atttypids[i] = attr->atttypid;
+ atttypmods[i] = attr->atttypmod;
+ atttypcolls[i] = attr->attcollation;
+ ReleaseSysCache(atup);
+ }
+
+ /*
+ * After all the positive number attnums in stxkeys come the negative
+ * numbers (if any) which represent expressions in the order that they
+ * appear in stxdexprs. Because the expressions are always
+ * monotonically decreasing from -1, there is no point in looking at
+ * the values in stxkeys, it's enough to know how many of them there
+ * are.
+ */
+ for (int i = numattnums; i < numattrs; i++)
+ {
+ Node *expr = list_nth(exprs, i - numattnums);
+
+ atttypids[i] = exprType(expr);
+ atttypmods[i] = exprTypmod(expr);
+ atttypcolls[i] = exprCollation(expr);
+ }
+ }
+
/*
* Populate the pg_statistic_ext_data result tuple.
*/
statext_dependencies_free(dependencies);
}
+ if (has.mcv)
+ {
+ Datum datum;
+ bool val_ok = false;
+
+ datum = import_mcv(PG_GETARG_ARRAYTYPE_P(MOST_COMMON_VALS_ARG),
+ PG_GETARG_ARRAYTYPE_P(MOST_COMMON_FREQS_ARG),
+ PG_GETARG_ARRAYTYPE_P(MOST_COMMON_BASE_FREQS_ARG),
+ atttypids, atttypmods, atttypcolls, numattrs,
+ &val_ok);
+
+ if (val_ok)
+ {
+ Assert(datum != (Datum) 0);
+ values[Anum_pg_statistic_ext_data_stxdmcv - 1] = datum;
+ nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = false;
+ replaces[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
+ }
+ else
+ success = false;
+ }
+
upsert_pg_statistic_ext_data(values, nulls, replaces);
cleanup:
heap_freetuple(tup);
if (pg_stext != NULL)
table_close(pg_stext, RowExclusiveLock);
+ if (atttypids != NULL)
+ pfree(atttypids);
+ if (atttypmods != NULL)
+ pfree(atttypmods);
+ if (atttypcolls != NULL)
+ pfree(atttypcolls);
return success;
}
+/*
+ * Consistency checks to ensure that other mcvlist arrays are in alignment
+ * with the mcv array.
+ */
+static bool
+check_mcvlist_array(const ArrayType *arr, int argindex, int required_ndims,
+ int mcv_length)
+{
+ if (ARR_NDIM(arr) != required_ndims)
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse array \"%s\": incorrect number of dimensions (%d required)",
+ extarginfo[argindex].argname, required_ndims));
+ return false;
+ }
+
+ if (array_contains_nulls(arr))
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse array \"%s\": NULL value found",
+ extarginfo[argindex].argname));
+ return false;
+ }
+
+ if (ARR_DIMS(arr)[0] != mcv_length)
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse array \"%s\": incorrect number of elements (same as \"%s\" required)",
+ extarginfo[argindex].argname,
+ extarginfo[MOST_COMMON_VALS_ARG].argname));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Create the stxdmcv datum from the equal-sized arrays of most common values,
+ * their null flags, and the frequency and base frequency associated with
+ * each value.
+ */
+static Datum
+import_mcv(const ArrayType *mcv_arr, const ArrayType *freqs_arr,
+ const ArrayType *base_freqs_arr, Oid *atttypids, int32 *atttypmods,
+ Oid *atttypcolls, int numattrs, bool *ok)
+{
+ int nitems;
+ Datum *mcv_elems;
+ bool *mcv_nulls;
+ int check_nummcv;
+ Datum mcv = (Datum) 0;
+
+ *ok = false;
+
+ /*
+ * mcv_arr is an array of arrays. Each inner array must have the same
+ * number of elements "numattrs".
+ */
+ if (ARR_NDIM(mcv_arr) != 2)
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse array \"%s\": incorrect number of dimensions (%d required)",
+ extarginfo[MOST_COMMON_VALS_ARG].argname, 2));
+ goto mcv_error;
+ }
+
+ if (ARR_DIMS(mcv_arr)[1] != numattrs)
+ {
+ ereport(WARNING,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse array \"%s\": found %d attributes but expected %d",
+ extarginfo[MOST_COMMON_VALS_ARG].argname,
+ ARR_DIMS(mcv_arr)[1], numattrs));
+ goto mcv_error;
+ }
+
+ /*
+ * "most_common_freqs" and "most_common_base_freqs" arrays must be of the
+ * same length, one-dimension and cannot contain NULLs. We use mcv_arr as
+ * the reference array for determining their length.
+ */
+ nitems = ARR_DIMS(mcv_arr)[0];
+ if (!check_mcvlist_array(freqs_arr, MOST_COMMON_FREQS_ARG, 1, nitems) ||
+ !check_mcvlist_array(base_freqs_arr, MOST_COMMON_BASE_FREQS_ARG, 1, nitems))
+ {
+ /* inconsistent input arrays found */
+ goto mcv_error;
+ }
+
+ /*
+ * This part builds the contents for "most_common_val_nulls", based on the
+ * values from "most_common_vals".
+ */
+ deconstruct_array_builtin(mcv_arr, TEXTOID, &mcv_elems,
+ &mcv_nulls, &check_nummcv);
+
+ mcv = statext_mcv_import(WARNING, numattrs,
+ atttypids, atttypmods, atttypcolls,
+ nitems, mcv_elems, mcv_nulls,
+ (float8 *) ARR_DATA_PTR(freqs_arr),
+ (float8 *) ARR_DATA_PTR(base_freqs_arr));
+
+ *ok = (mcv != (Datum) 0);
+
+mcv_error:
+ return mcv;
+}
+
/*
* Remove an existing pg_statistic_ext_data row for a given pg_statistic_ext
* row and "inherited" pair.
}
pfree(mcvlist);
}
+
+/*
+ * Create the MCV composite datum, which is a serialization of an array of
+ * MCVItems.
+ *
+ * The inputs consist of four separate arrays of equal length "numitems"
+ * (mcv_elems, mcv_nulls, freqs and base_freqs) that form the basics of
+ * what is stored in the catalogs. These form an array of composite
+ * records defined by the three atttypX arrays of equal length "numattrs".
+ *
+ * If any data element fails to convert to the input type specified for that
+ * attribute, then function will return a NULL Datum if elevel < ERROR.
+ */
+Datum
+statext_mcv_import(int elevel, int numattrs,
+ Oid *atttypids, int32 *atttypmods, Oid *atttypcolls,
+ int nitems, Datum *mcv_elems, bool *mcv_nulls,
+ float8 *freqs, float8 *base_freqs)
+{
+ MCVList *mcvlist;
+ bytea *bytes;
+ VacAttrStats **vastats;
+
+ /*
+ * Allocate the MCV list structure, set the global parameters.
+ */
+ mcvlist = (MCVList *) palloc0(offsetof(MCVList, items) +
+ (sizeof(MCVItem) * nitems));
+
+ mcvlist->magic = STATS_MCV_MAGIC;
+ mcvlist->type = STATS_MCV_TYPE_BASIC;
+ mcvlist->ndimensions = numattrs;
+ mcvlist->nitems = nitems;
+
+ /* Set the values for the 1-D arrays and allocate space for the 2-D arrays */
+ for (int i = 0; i < nitems; i++)
+ {
+ MCVItem *item = &mcvlist->items[i];
+
+ item->frequency = freqs[i];
+ item->base_frequency = base_freqs[i];
+ item->values = (Datum *) palloc0_array(Datum, numattrs);
+ item->isnull = (bool *) palloc0_array(bool, numattrs);
+ }
+
+ /*
+ * Walk through each dimension, determine the input function for that
+ * type, and then attempt to convert all values in that column via that
+ * function. We approach this column-wise because it is simpler to deal
+ * with one input function at time, and possibly more cache-friendly.
+ */
+ for (int j = 0; j < numattrs; j++)
+ {
+ FmgrInfo finfo;
+ Oid ioparam;
+ Oid infunc;
+ int index = j;
+
+ getTypeInputInfo(atttypids[j], &infunc, &ioparam);
+ fmgr_info(infunc, &finfo);
+
+ /* store info about data type OIDs */
+ mcvlist->types[j] = atttypids[j];
+
+ for (int i = 0; i < nitems; i++)
+ {
+ MCVItem *item = &mcvlist->items[i];
+
+ if (mcv_nulls[index])
+ {
+ /* NULL value detected, hence no input to process */
+ item->values[j] = (Datum) 0;
+ item->isnull[j] = true;
+ }
+ else
+ {
+ char *s = TextDatumGetCString(mcv_elems[index]);
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ if (!InputFunctionCallSafe(&finfo, s, ioparam, atttypmods[j],
+ (Node *) &escontext, &item->values[j]))
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse MCV element \"%s\": incorrect value", s)));
+ pfree(s);
+ goto error;
+ }
+
+ pfree(s);
+ }
+
+ index += numattrs;
+ }
+ }
+
+ /*
+ * The function statext_mcv_serialize() requires an array of pointers to
+ * VacAttrStats records, but only a few fields within those records have
+ * to be filled out.
+ */
+ vastats = (VacAttrStats **) palloc0_array(VacAttrStats *, numattrs);
+
+ for (int i = 0; i < numattrs; i++)
+ {
+ Oid typid = atttypids[i];
+ HeapTuple typtuple;
+
+ typtuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typid));
+
+ if (!HeapTupleIsValid(typtuple))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+
+ vastats[i] = palloc0_object(VacAttrStats);
+
+ vastats[i]->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
+ vastats[i]->attrtypid = typid;
+ vastats[i]->attrcollid = atttypcolls[i];
+ }
+
+ bytes = statext_mcv_serialize(mcvlist, vastats);
+
+ for (int i = 0; i < numattrs; i++)
+ {
+ pfree(vastats[i]);
+ }
+ pfree((void *) vastats);
+
+ pfree(mcv_elems);
+ pfree(mcv_nulls);
+
+ if (bytes == NULL)
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not import MCV list")));
+ goto error;
+ }
+
+ return PointerGetDatum(bytes);
+
+error:
+ statext_mcv_free(mcvlist);
+ return (Datum) 0;
+}
*--------
*/
if (fout->remoteVersion >= 190000)
- appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies ");
+ appendPQExpBufferStr(pq, "e.n_distinct, e.dependencies, ");
else
appendPQExpBufferStr(pq,
"( "
" '" PG_DEPENDENCIES_KEY_DEGREE "', "
" kv.value::double precision )) "
"FROM json_each_text(e.dependencies::text::json) AS kv "
- ") AS dependencies ");
+ ") AS dependencies, ");
+
+ /* MCV was introduced v13 */
+ if (fout->remoteVersion >= 130000)
+ appendPQExpBufferStr(pq,
+ "e.most_common_vals, e.most_common_freqs, "
+ "e.most_common_base_freqs ");
+ else
+ appendPQExpBufferStr(pq,
+ "NULL AS most_common_vals, NULL AS most_common_freqs, "
+ "NULL AS most_common_base_freqs ");
/* pg_stats_ext introduced in v12 */
if (fout->remoteVersion >= 120000)
int i_inherited = PQfnumber(res, "inherited");
int i_ndistinct = PQfnumber(res, "n_distinct");
int i_dependencies = PQfnumber(res, "dependencies");
+ int i_mcv = PQfnumber(res, "most_common_vals");
+ int i_mcf = PQfnumber(res, "most_common_freqs");
+ int i_mcbf = PQfnumber(res, "most_common_base_freqs");
for (int i = 0; i < nstats; i++)
{
appendNamedArgument(out, fout, "dependencies", "pg_dependencies",
PQgetvalue(res, i, i_dependencies));
+ if (!PQgetisnull(res, i, i_mcv))
+ appendNamedArgument(out, fout, "most_common_vals", "text[]",
+ PQgetvalue(res, i, i_mcv));
+
+ if (!PQgetisnull(res, i, i_mcf))
+ appendNamedArgument(out, fout, "most_common_freqs", "double precision[]",
+ PQgetvalue(res, i, i_mcf));
+
+ if (!PQgetisnull(res, i, i_mcbf))
+ appendNamedArgument(out, fout, "most_common_base_freqs", "double precision[]",
+ PQgetvalue(res, i, i_mcbf));
+
appendPQExpBufferStr(out, "\n);\n");
}
extern bytea *statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats);
extern MCVList *statext_mcv_deserialize(bytea *data);
extern void statext_mcv_free(MCVList *mcvlist);
+extern Datum statext_mcv_import(int elevel, int numattrs, Oid *atttypids,
+ int32 *atttypmods, Oid *atttypcolls,
+ int nitems, Datum *mcv_elems,
+ bool *mcv_nulls, float8 *freqs,
+ float8 *base_freqs);
extern MultiSortSupport multi_sort_init(int ndims);
extern void multi_sort_add_dimension(MultiSortSupport mss, int sortdim,
CREATE STATISTICS stats_import.test_stat_dependencies (dependencies)
ON name, comp
FROM stats_import.test;
+CREATE STATISTICS stats_import.test_stat_mcv (mcv)
+ ON name, comp
+ FROM stats_import.test;
CREATE STATISTICS stats_import.test_stat_ndistinct_exprs (ndistinct)
ON lower(name), upper(name)
FROM stats_import.test;
CREATE STATISTICS stats_import.test_stat_dependencies_exprs (dependencies)
ON lower(name), upper(name)
FROM stats_import.test;
+CREATE STATISTICS stats_import.test_stat_mcv_exprs (mcv)
+ ON lower(name), upper(name)
+ FROM stats_import.test;
-- Generate statistics on table with data
ANALYZE stats_import.test;
CREATE TABLE stats_import.test_clone ( LIKE stats_import.test )
t
(1 row)
+-- ok: MCV with expressions
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv_exprs',
+ 'inherited', false,
+ 'most_common_vals', '{{four,FOUR},{one,NULL},{NULL,TRE},{two,TWO}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.99}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.023,0.087}'::double precision[]);
+ pg_restore_extended_stats
+---------------------------
+ t
+(1 row)
+
-- Check the presence of the restored stats, for each object.
SELECT replace(e.n_distinct, '}, ', E'},\n') AS n_distinct
FROM pg_stats_ext AS e
{"attributes": [-2], "dependency": -1, "degree": 1.000000}]
(1 row)
+SELECT e.most_common_vals, e.most_common_val_nulls,
+ e.most_common_freqs, e.most_common_base_freqs
+FROM pg_stats_ext AS e
+WHERE e.statistics_schemaname = 'stats_import' AND
+ e.statistics_name = 'test_stat_mcv_exprs' AND
+ e.inherited = false \gx
+-[ RECORD 1 ]----------+----------------------------------------------
+most_common_vals | {{four,FOUR},{one,NULL},{NULL,TRE},{two,TWO}}
+most_common_val_nulls | {{f,f},{f,t},{t,f},{f,f}}
+most_common_freqs | {0.25,0.25,0.25,0.99}
+most_common_base_freqs | {0.0625,0.0625,0.023,0.087}
+
+-- Incorrect extended stats kind, mcv not supported
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_dependencies',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: cannot specify parameters "most_common_vals", "most_common_freqs" or "most_common_base_freqs"
+HINT: Extended statistics object "stats_import"."test_stat_dependencies" does not support statistics of this type.
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- MCV requires all three parameters
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: could not use "most_common_vals", "most_common_freqs" and "most_common_base_freqs": missing one or more parameters
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: could not use "most_common_vals", "most_common_freqs" and "most_common_base_freqs": missing one or more parameters
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[]);
+WARNING: could not use "most_common_vals", "most_common_freqs" and "most_common_base_freqs": missing one or more parameters
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- most_common_vals that is not 2-D
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{four,NULL}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: could not parse array "most_common_vals": incorrect number of dimensions (2 required)
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- most_common_freqs with length not matching with most_common_vals.
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: could not parse array "most_common_freqs": incorrect number of elements (same as "most_common_vals" required)
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- most_common_base_freqs with length not matching most_common_vals.
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625}'::double precision[]);
+WARNING: could not parse array "most_common_base_freqs": incorrect number of elements (same as "most_common_vals" required)
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- mcv attributes not matching object definition
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL,0,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")",1,2},
+ {tre,"(3,3.3,TRE,03-03-2003,)",-1,3},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")",1,2}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.00390625,0.015625,0.00390625,0.015625}'::double precision[]);
+WARNING: could not parse array "most_common_vals": found 4 attributes but expected 2
+ pg_restore_extended_stats
+---------------------------
+ f
+(1 row)
+
+-- ok: mcv
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+ pg_restore_extended_stats
+---------------------------
+ t
+(1 row)
+
+SELECT replace(e.most_common_vals::text, '},', E'},\n ') AS mcvs,
+ e.most_common_val_nulls,
+ e.most_common_freqs, e.most_common_base_freqs
+FROM pg_stats_ext AS e
+WHERE e.statistics_schemaname = 'stats_import' AND
+ e.statistics_name = 'test_stat_mcv' AND
+ e.inherited = false
+\gx
+-[ RECORD 1 ]----------+------------------------------------------------------------------
+mcvs | {{four,NULL}, +
+ | {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},+
+ | {tre,"(3,3.3,TRE,03-03-2003,)"}, +
+ | {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}
+most_common_val_nulls | {{f,t},{f,f},{f,f},{f,f}}
+most_common_freqs | {0.25,0.25,0.25,0.25}
+most_common_base_freqs | {0.0625,0.0625,0.0625,0.0625}
+
DROP SCHEMA stats_import CASCADE;
NOTICE: drop cascades to 7 other objects
DETAIL: drop cascades to type stats_import.complex_type
ON name, comp
FROM stats_import.test;
+CREATE STATISTICS stats_import.test_stat_mcv (mcv)
+ ON name, comp
+ FROM stats_import.test;
+
CREATE STATISTICS stats_import.test_stat_ndistinct_exprs (ndistinct)
ON lower(name), upper(name)
FROM stats_import.test;
ON lower(name), upper(name)
FROM stats_import.test;
+CREATE STATISTICS stats_import.test_stat_mcv_exprs (mcv)
+ ON lower(name), upper(name)
+ FROM stats_import.test;
+
-- Generate statistics on table with data
ANALYZE stats_import.test;
'dependencies', '[{"attributes": [-1], "dependency": -2, "degree": 1.000000},
{"attributes": [-2], "dependency": -1, "degree": 1.000000}]'::pg_dependencies);
+-- ok: MCV with expressions
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv_exprs',
+ 'inherited', false,
+ 'most_common_vals', '{{four,FOUR},{one,NULL},{NULL,TRE},{two,TWO}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.99}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.023,0.087}'::double precision[]);
+
-- Check the presence of the restored stats, for each object.
SELECT replace(e.n_distinct, '}, ', E'},\n') AS n_distinct
FROM pg_stats_ext AS e
e.statistics_name = 'test_stat_dependencies_exprs' AND
e.inherited = false;
+SELECT e.most_common_vals, e.most_common_val_nulls,
+ e.most_common_freqs, e.most_common_base_freqs
+FROM pg_stats_ext AS e
+WHERE e.statistics_schemaname = 'stats_import' AND
+ e.statistics_name = 'test_stat_mcv_exprs' AND
+ e.inherited = false \gx
+
+-- Incorrect extended stats kind, mcv not supported
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_dependencies',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+
+-- MCV requires all three parameters
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[]);
+
+-- most_common_vals that is not 2-D
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{four,NULL}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+
+-- most_common_freqs with length not matching with most_common_vals.
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+
+-- most_common_base_freqs with length not matching most_common_vals.
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625}'::double precision[]);
+
+-- mcv attributes not matching object definition
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL,0,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")",1,2},
+ {tre,"(3,3.3,TRE,03-03-2003,)",-1,3},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")",1,2}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.00390625,0.015625,0.00390625,0.015625}'::double precision[]);
+
+-- ok: mcv
+SELECT pg_catalog.pg_restore_extended_stats(
+ 'schemaname', 'stats_import',
+ 'relname', 'test',
+ 'statistics_schemaname', 'stats_import',
+ 'statistics_name', 'test_stat_mcv',
+ 'inherited', false,
+ 'most_common_vals', '{{four,NULL},
+ {one,"(1,1.1,ONE,01-01-2001,\"{\"\"xkey\"\": \"\"xval\"\"}\")"},
+ {tre,"(3,3.3,TRE,03-03-2003,)"},
+ {two,"(2,2.2,TWO,02-02-2002,\"[true, 4, \"\"six\"\"]\")"}}'::text[],
+ 'most_common_freqs', '{0.25,0.25,0.25,0.25}'::double precision[],
+ 'most_common_base_freqs', '{0.0625,0.0625,0.0625,0.0625}'::double precision[]);
+
+SELECT replace(e.most_common_vals::text, '},', E'},\n ') AS mcvs,
+ e.most_common_val_nulls,
+ e.most_common_freqs, e.most_common_base_freqs
+FROM pg_stats_ext AS e
+WHERE e.statistics_schemaname = 'stats_import' AND
+ e.statistics_name = 'test_stat_mcv' AND
+ e.inherited = false
+\gx
+
DROP SCHEMA stats_import CASCADE;