mirror of
https://github.com/postgres/postgres.git
synced 2026-01-26 09:41:40 +03:00
Add pg_restore_extended_stats()
This function closely mirror its relation and attribute counterparts, but for extended statistics (i.e. CREATE STATISTICS) objects, being able to restore extended statistics for an extended stats object. Like the other functions, the goal of this feature is to ease the dump or upgrade of clusters so as ANALYZE would not be required anymore after these operations, stats being directly loaded into the target cluster without any post-dump/upgrade computation. The caller of this function needs the following arguments for the extended stats to restore: - The name of the relation. - The schema name of the relation. - The name of the extended stats object. - The schema name of the extended stats object. - If the stats are inherited or not. - One or more extended stats kind with its data. This commit adds only support for the restore of the extended statistics kind "n_distinct", building the basic infrastructure for the restore of more extended statistics kinds in follow-up commits, including MVC and dependencies. The support for "n_distinct" is eased in this commit thanks to the previous work done particularly in commits1f927cce44and44eba8f06e, that have added the input function for the type pg_ndistinct, used as data type in input of this new restore function. Bump catalog version. Author: Corey Huinker <corey.huinker@gmail.com> Co-authored-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://postgr.es/m/CADkLM=dpz3KFnqP-dgJ-zvRvtjsa8UZv8wDAQdqho=qN3kX0Zg@mail.gmail.com
This commit is contained in:
@@ -2165,6 +2165,85 @@ SELECT pg_restore_attribute_stats(
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
<primary>pg_restore_extended_stats</primary>
|
||||
</indexterm>
|
||||
<function>pg_restore_extended_stats</function> (
|
||||
<literal>VARIADIC</literal> <parameter>kwargs</parameter> <type>"any"</type> )
|
||||
<returnvalue>boolean</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Creates or updates statistics for statistics objects. Ordinarily,
|
||||
these statistics are collected automatically or updated as a part of
|
||||
<xref linkend="sql-vacuum"/> or <xref linkend="sql-analyze"/>, so
|
||||
it's not necessary to call this function. However, it is useful
|
||||
after a restore to enable the optimizer to choose better plans if
|
||||
<command>ANALYZE</command> has not been run yet.
|
||||
</para>
|
||||
<para>
|
||||
The tracked statistics may change from version to version, so
|
||||
arguments are passed as pairs of <replaceable>argname</replaceable>
|
||||
and <replaceable>argvalue</replaceable> in the form:
|
||||
<programlisting>
|
||||
SELECT pg_restore_extended_stats(
|
||||
'<replaceable>arg1name</replaceable>', '<replaceable>arg1value</replaceable>'::<replaceable>arg1type</replaceable>,
|
||||
'<replaceable>arg2name</replaceable>', '<replaceable>arg2value</replaceable>'::<replaceable>arg2type</replaceable>,
|
||||
'<replaceable>arg3name</replaceable>', '<replaceable>arg3value</replaceable>'::<replaceable>arg3type</replaceable>);
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
For example, to set the <structfield>n_distinct</structfield>,
|
||||
<structfield>dependencies</structfield>, and <structfield>exprs</structfield>
|
||||
values for the statistics object <structname>myschema.mystatsobj</structname>:
|
||||
<programlisting>
|
||||
SELECT pg_restore_extended_stats(
|
||||
'schemaname', 'tab_schema'::name,
|
||||
'relname', 'tab_name'::name,
|
||||
'statistics_schemaname', 'stats_schema'::name,
|
||||
'statistics_name', 'stats_name'::name,
|
||||
'inherited', false,
|
||||
'n_distinct', '[{"attributes" : [2,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The required arguments are <literal>schemaname</literal> with a value
|
||||
of type <type>name</type>, for the schema of the table to which the
|
||||
statistics are related to, <literal>relname</literal> with a value
|
||||
of type <type>name</type>, for the table to which the statistics are
|
||||
related to, <literal>statistics_schemaname</literal>
|
||||
with a value of type <type>name</type>, which specifies the statistics
|
||||
object's schema, <literal>statistics_name</literal> with a value of
|
||||
type <type>name</type>, which specifies the name of the statistics
|
||||
object and <literal>inherited</literal>, which specifies whether
|
||||
the statistics include values from child tables.
|
||||
</para>
|
||||
<para>
|
||||
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>.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, this function accepts argument name
|
||||
<literal>version</literal> of type <type>integer</type>, which
|
||||
specifies the server version from which the statistics originated.
|
||||
This is anticipated to be helpful in porting statistics from older
|
||||
versions of <productname>PostgreSQL</productname>.
|
||||
</para>
|
||||
<para>
|
||||
Minor errors are reported as a <literal>WARNING</literal> and
|
||||
ignored, and remaining statistics will still be restored. If all
|
||||
specified statistics are successfully restored, returns
|
||||
<literal>true</literal>, otherwise <literal>false</literal>.
|
||||
</para>
|
||||
<para>
|
||||
The caller must have the <literal>MAINTAIN</literal> privilege on the
|
||||
table or be the owner of the database.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry role="func_table_entry">
|
||||
<para role="func_signature">
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
#include "catalog/pg_statistic_ext_data.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "statistics/extended_stats_internal.h"
|
||||
#include "statistics/stat_utils.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
@@ -42,6 +44,7 @@ enum extended_stats_argnum
|
||||
STATSCHEMA_ARG,
|
||||
STATNAME_ARG,
|
||||
INHERITED_ARG,
|
||||
NDISTINCT_ARG,
|
||||
NUM_EXTENDED_STATS_ARGS,
|
||||
};
|
||||
|
||||
@@ -56,13 +59,33 @@ static struct StatsArgInfo extarginfo[] =
|
||||
[STATSCHEMA_ARG] = {"statistics_schemaname", TEXTOID},
|
||||
[STATNAME_ARG] = {"statistics_name", TEXTOID},
|
||||
[INHERITED_ARG] = {"inherited", BOOLOID},
|
||||
[NDISTINCT_ARG] = {"n_distinct", PG_NDISTINCTOID},
|
||||
[NUM_EXTENDED_STATS_ARGS] = {0},
|
||||
};
|
||||
|
||||
static bool extended_statistics_update(FunctionCallInfo fcinfo);
|
||||
|
||||
static HeapTuple get_pg_statistic_ext(Relation pg_stext, Oid nspoid,
|
||||
const char *stxname);
|
||||
static bool delete_pg_statistic_ext_data(Oid stxoid, bool inherited);
|
||||
|
||||
/*
|
||||
* Track the extended statistics kinds expected for a pg_statistic_ext
|
||||
* tuple.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool ndistinct;
|
||||
bool dependencies;
|
||||
bool mcv;
|
||||
bool expressions;
|
||||
} StakindFlags;
|
||||
|
||||
static void expand_stxkind(HeapTuple tup, StakindFlags *enabled);
|
||||
static void upsert_pg_statistic_ext_data(const Datum *values,
|
||||
const bool *nulls,
|
||||
const bool *replaces);
|
||||
|
||||
/*
|
||||
* Fetch a pg_statistic_ext row by name and namespace OID.
|
||||
*/
|
||||
@@ -109,6 +132,278 @@ get_pg_statistic_ext(Relation pg_stext, Oid nspoid, const char *stxname)
|
||||
return SearchSysCacheCopy1(STATEXTOID, ObjectIdGetDatum(stxoid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the stxkind column so that we know which stats types to expect,
|
||||
* returning a StakindFlags set depending on the stats kinds expected by
|
||||
* a pg_statistic_ext tuple.
|
||||
*/
|
||||
static void
|
||||
expand_stxkind(HeapTuple tup, StakindFlags *enabled)
|
||||
{
|
||||
Datum datum;
|
||||
ArrayType *arr;
|
||||
char *kinds;
|
||||
|
||||
datum = SysCacheGetAttrNotNull(STATEXTOID,
|
||||
tup,
|
||||
Anum_pg_statistic_ext_stxkind);
|
||||
arr = DatumGetArrayTypeP(datum);
|
||||
if (ARR_NDIM(arr) != 1 || ARR_HASNULL(arr) || ARR_ELEMTYPE(arr) != CHAROID)
|
||||
elog(ERROR, "stxkind is not a one-dimension char array");
|
||||
|
||||
kinds = (char *) ARR_DATA_PTR(arr);
|
||||
|
||||
for (int i = 0; i < ARR_DIMS(arr)[0]; i++)
|
||||
{
|
||||
switch (kinds[i])
|
||||
{
|
||||
case STATS_EXT_NDISTINCT:
|
||||
enabled->ndistinct = true;
|
||||
break;
|
||||
case STATS_EXT_DEPENDENCIES:
|
||||
enabled->dependencies = true;
|
||||
break;
|
||||
case STATS_EXT_MCV:
|
||||
enabled->mcv = true;
|
||||
break;
|
||||
case STATS_EXT_EXPRESSIONS:
|
||||
enabled->expressions = true;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "incorrect stxkind %c found", kinds[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the actual storage of a pg_statistic_ext_data tuple.
|
||||
*/
|
||||
static void
|
||||
upsert_pg_statistic_ext_data(const Datum *values, const bool *nulls,
|
||||
const bool *replaces)
|
||||
{
|
||||
Relation pg_stextdata;
|
||||
HeapTuple stxdtup;
|
||||
HeapTuple newtup;
|
||||
|
||||
pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock);
|
||||
|
||||
stxdtup = SearchSysCache2(STATEXTDATASTXOID,
|
||||
values[Anum_pg_statistic_ext_data_stxoid - 1],
|
||||
values[Anum_pg_statistic_ext_data_stxdinherit - 1]);
|
||||
|
||||
if (HeapTupleIsValid(stxdtup))
|
||||
{
|
||||
newtup = heap_modify_tuple(stxdtup,
|
||||
RelationGetDescr(pg_stextdata),
|
||||
values,
|
||||
nulls,
|
||||
replaces);
|
||||
CatalogTupleUpdate(pg_stextdata, &newtup->t_self, newtup);
|
||||
ReleaseSysCache(stxdtup);
|
||||
}
|
||||
else
|
||||
{
|
||||
newtup = heap_form_tuple(RelationGetDescr(pg_stextdata), values, nulls);
|
||||
CatalogTupleInsert(pg_stextdata, newtup);
|
||||
}
|
||||
|
||||
heap_freetuple(newtup);
|
||||
|
||||
CommandCounterIncrement();
|
||||
|
||||
table_close(pg_stextdata, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert or update an extended statistics object.
|
||||
*
|
||||
* Major errors, such as the table not existing or permission errors, are
|
||||
* reported as ERRORs. There are a couple of paths that generate a WARNING,
|
||||
* like when the statistics object or its schema do not exist, a conversion
|
||||
* failure on one statistic kind, or when other statistic kinds may still
|
||||
* be updated.
|
||||
*/
|
||||
static bool
|
||||
extended_statistics_update(FunctionCallInfo fcinfo)
|
||||
{
|
||||
char *relnspname;
|
||||
char *relname;
|
||||
Oid nspoid;
|
||||
char *nspname;
|
||||
char *stxname;
|
||||
bool inherited;
|
||||
Relation pg_stext = NULL;
|
||||
HeapTuple tup = NULL;
|
||||
|
||||
StakindFlags enabled = {false, false, false, false};
|
||||
StakindFlags has = {false, false, false, false};
|
||||
|
||||
Form_pg_statistic_ext stxform;
|
||||
|
||||
Datum values[Natts_pg_statistic_ext_data] = {0};
|
||||
bool nulls[Natts_pg_statistic_ext_data];
|
||||
bool replaces[Natts_pg_statistic_ext_data] = {0};
|
||||
bool success = true;
|
||||
int numexprs = 0;
|
||||
|
||||
/* arrays of type info, if we need them */
|
||||
Oid relid;
|
||||
Oid locked_table = InvalidOid;
|
||||
|
||||
/*
|
||||
* Fill out the StakindFlags "has" structure based on which parameters
|
||||
* were provided to the function.
|
||||
*/
|
||||
has.ndistinct = !PG_ARGISNULL(NDISTINCT_ARG);
|
||||
|
||||
if (RecoveryInProgress())
|
||||
{
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("recovery is in progress"),
|
||||
errhint("Statistics cannot be modified during recovery."));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* relation arguments */
|
||||
stats_check_required_arg(fcinfo, extarginfo, RELSCHEMA_ARG);
|
||||
relnspname = TextDatumGetCString(PG_GETARG_DATUM(RELSCHEMA_ARG));
|
||||
stats_check_required_arg(fcinfo, extarginfo, RELNAME_ARG);
|
||||
relname = TextDatumGetCString(PG_GETARG_DATUM(RELNAME_ARG));
|
||||
|
||||
/* extended statistics arguments */
|
||||
stats_check_required_arg(fcinfo, extarginfo, STATSCHEMA_ARG);
|
||||
nspname = TextDatumGetCString(PG_GETARG_DATUM(STATSCHEMA_ARG));
|
||||
stats_check_required_arg(fcinfo, extarginfo, STATNAME_ARG);
|
||||
stxname = TextDatumGetCString(PG_GETARG_DATUM(STATNAME_ARG));
|
||||
stats_check_required_arg(fcinfo, extarginfo, INHERITED_ARG);
|
||||
inherited = PG_GETARG_BOOL(INHERITED_ARG);
|
||||
|
||||
/*
|
||||
* First open the relation where we expect to find the statistics. This
|
||||
* is similar to relation and attribute statistics, so as ACL checks are
|
||||
* done before any locks are taken, even before any attempts related to
|
||||
* the extended stats object.
|
||||
*/
|
||||
relid = RangeVarGetRelidExtended(makeRangeVar(relnspname, relname, -1),
|
||||
ShareUpdateExclusiveLock, 0,
|
||||
RangeVarCallbackForStats, &locked_table);
|
||||
|
||||
nspoid = get_namespace_oid(nspname, true);
|
||||
if (nspoid == InvalidOid)
|
||||
{
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find schema \"%s\"", nspname));
|
||||
success = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pg_stext = table_open(StatisticExtRelationId, RowExclusiveLock);
|
||||
tup = get_pg_statistic_ext(pg_stext, nspoid, stxname);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find extended statistics object \"%s\".\"%s\"",
|
||||
quote_identifier(nspname),
|
||||
quote_identifier(stxname)));
|
||||
success = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stxform = (Form_pg_statistic_ext) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* The relation tracked by the stats object has to match with the relation
|
||||
* we have already locked.
|
||||
*/
|
||||
if (stxform->stxrelid != relid)
|
||||
{
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("could not restore extended statistics object \"%s\".\"%s\": incorrect relation \"%s\".\"%s\" specified",
|
||||
quote_identifier(nspname),
|
||||
quote_identifier(stxname),
|
||||
quote_identifier(relnspname),
|
||||
quote_identifier(relname)));
|
||||
|
||||
success = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Find out what extended statistics kinds we should expect. */
|
||||
expand_stxkind(tup, &enabled);
|
||||
|
||||
/*
|
||||
* If the object cannot support ndistinct, we should not have data for it.
|
||||
*/
|
||||
if (has.ndistinct && !enabled.ndistinct)
|
||||
{
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("cannot not specify parameter \"%s\"",
|
||||
extarginfo[NDISTINCT_ARG].argname),
|
||||
errhint("Extended statistics object \"%s\".\"%s\" does not support statistics of this type.",
|
||||
quote_identifier(nspname),
|
||||
quote_identifier(stxname)));
|
||||
|
||||
has.ndistinct = false;
|
||||
success = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate the pg_statistic_ext_data result tuple.
|
||||
*/
|
||||
|
||||
/* Primary Key: cannot be NULL or replaced. */
|
||||
values[Anum_pg_statistic_ext_data_stxoid - 1] = ObjectIdGetDatum(stxform->oid);
|
||||
values[Anum_pg_statistic_ext_data_stxdinherit - 1] = BoolGetDatum(inherited);
|
||||
|
||||
/* All unspecified parameters will be left unmodified */
|
||||
nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
|
||||
nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = true;
|
||||
nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = true;
|
||||
nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = true;
|
||||
|
||||
/*
|
||||
* For each stats kind, deserialize the data at hand and perform a round
|
||||
* of validation. The resulting tuple is filled with a set of updated
|
||||
* values.
|
||||
*/
|
||||
|
||||
if (has.ndistinct)
|
||||
{
|
||||
Datum ndistinct_datum = PG_GETARG_DATUM(NDISTINCT_ARG);
|
||||
bytea *data = DatumGetByteaPP(ndistinct_datum);
|
||||
MVNDistinct *ndistinct = statext_ndistinct_deserialize(data);
|
||||
|
||||
if (statext_ndistinct_validate(ndistinct, &stxform->stxkeys,
|
||||
numexprs, WARNING))
|
||||
{
|
||||
values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = ndistinct_datum;
|
||||
nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = false;
|
||||
replaces[Anum_pg_statistic_ext_data_stxdndistinct - 1] = true;
|
||||
}
|
||||
else
|
||||
success = false;
|
||||
|
||||
statext_ndistinct_free(ndistinct);
|
||||
}
|
||||
|
||||
upsert_pg_statistic_ext_data(values, nulls, replaces);
|
||||
|
||||
cleanup:
|
||||
if (HeapTupleIsValid(tup))
|
||||
heap_freetuple(tup);
|
||||
if (pg_stext != NULL)
|
||||
table_close(pg_stext, RowExclusiveLock);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an existing pg_statistic_ext_data row for a given pg_statistic_ext
|
||||
* row and "inherited" pair.
|
||||
@@ -139,6 +434,31 @@ delete_pg_statistic_ext_data(Oid stxoid, bool inherited)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore (insert or replace) statistics for the given statistics object.
|
||||
*
|
||||
* This function accepts variadic arguments in key-value pairs, which are
|
||||
* given to stats_fill_fcinfo_from_arg_pairs to be mapped into positional
|
||||
* arguments.
|
||||
*/
|
||||
Datum
|
||||
pg_restore_extended_stats(PG_FUNCTION_ARGS)
|
||||
{
|
||||
LOCAL_FCINFO(positional_fcinfo, NUM_EXTENDED_STATS_ARGS);
|
||||
bool result = true;
|
||||
|
||||
InitFunctionCallInfoData(*positional_fcinfo, NULL, NUM_EXTENDED_STATS_ARGS,
|
||||
InvalidOid, NULL, NULL);
|
||||
|
||||
if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo, extarginfo))
|
||||
result = false;
|
||||
|
||||
if (!extended_statistics_update(positional_fcinfo))
|
||||
result = false;
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete statistics for the given statistics object.
|
||||
*/
|
||||
|
||||
@@ -57,6 +57,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202601221
|
||||
#define CATALOG_VERSION_NO 202601261
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12619,6 +12619,11 @@
|
||||
proargtypes => 'int4', prosrc => 'gist_translate_cmptype_common' },
|
||||
|
||||
# Extended Statistics functions
|
||||
{ oid => '9947', descr => 'restore statistics on extended statistics object',
|
||||
proname => 'pg_restore_extended_stats', provariadic => 'any',
|
||||
proisstrict => 'f', provolatile => 'v', proparallel => 'u',
|
||||
prorettype => 'bool', proargtypes => 'any', proargmodes => '{v}',
|
||||
proargnames => '{kwargs}', prosrc => 'pg_restore_extended_stats' },
|
||||
{ oid => '9948', descr => 'clear statistics on extended statistics object',
|
||||
proname => 'pg_clear_extended_stats', proisstrict => 'f', provolatile => 'v',
|
||||
proparallel => 'u', prorettype => 'void', proargtypes => 'text text text text bool',
|
||||
|
||||
@@ -1141,6 +1141,12 @@ CREATE INDEX is_odd ON stats_import.test(((comp).a % 2 = 1));
|
||||
CREATE STATISTICS stats_import.test_stat
|
||||
ON name, comp, lower(arange), array_length(tags,1)
|
||||
FROM stats_import.test;
|
||||
CREATE STATISTICS stats_import.test_stat_ndistinct (ndistinct)
|
||||
ON name, comp
|
||||
FROM stats_import.test;
|
||||
CREATE STATISTICS stats_import.test_stat_dependencies (dependencies)
|
||||
ON name, comp
|
||||
FROM stats_import.test;
|
||||
-- Generate statistics on table with data
|
||||
ANALYZE stats_import.test;
|
||||
CREATE TABLE stats_import.test_clone ( LIKE stats_import.test )
|
||||
@@ -1590,6 +1596,147 @@ RESET ROLE;
|
||||
REVOKE MAINTAIN ON stats_import.test FROM regress_test_extstat_clear;
|
||||
REVOKE ALL ON SCHEMA stats_import FROM regress_test_extstat_clear;
|
||||
DROP ROLE regress_test_extstat_clear;
|
||||
-- Tests for pg_restore_extended_stats().
|
||||
-- Invalid argument values.
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', NULL,
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
ERROR: argument "schemaname" must not be null
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', NULL,
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
ERROR: argument "relname" must not be null
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', NULL,
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
ERROR: argument "statistics_schemaname" must not be null
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', NULL,
|
||||
'inherited', false);
|
||||
ERROR: argument "statistics_name" must not be null
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', NULL);
|
||||
ERROR: argument "inherited" must not be null
|
||||
-- Missing objects
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'schema_not_exist',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
ERROR: schema "schema_not_exist" does not exist
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'table_not_exist',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
ERROR: relation "stats_import.table_not_exist" does not exist
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'schema_not_exist',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
WARNING: could not find schema "schema_not_exist"
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'ext_stats_not_exist',
|
||||
'inherited', false);
|
||||
WARNING: could not find extended statistics object "stats_import"."ext_stats_not_exist"
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Incorrect relation/extended stats combination
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
WARNING: could not restore extended statistics object "stats_import"."test_stat_clone": incorrect relation "stats_import"."test" specified
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- ndistinct value doesn't match object definition
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_ndistinct',
|
||||
'inherited', false,
|
||||
'n_distinct', '[{"attributes" : [1,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
WARNING: could not validate "pg_ndistinct" object: invalid attribute number 1 found
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Incorrect extended stats kind, ndistinct 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,
|
||||
'n_distinct', '[{"attributes" : [1,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
WARNING: cannot not specify parameter "n_distinct"
|
||||
HINT: Extended statistics object "stats_import"."test_stat_dependencies" does not support statistics of this type.
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- ok: ndistinct
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_ndistinct',
|
||||
'inherited', false,
|
||||
'n_distinct', '[{"attributes" : [2,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
pg_restore_extended_stats
|
||||
---------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT replace(e.n_distinct, '}, ', E'},\n') AS n_distinct
|
||||
FROM pg_stats_ext AS e
|
||||
WHERE e.statistics_schemaname = 'stats_import' AND
|
||||
e.statistics_name = 'test_stat_ndistinct' AND
|
||||
e.inherited = false;
|
||||
n_distinct
|
||||
------------------------------------------
|
||||
[{"attributes": [2, 3], "ndistinct": 4}]
|
||||
(1 row)
|
||||
|
||||
DROP SCHEMA stats_import CASCADE;
|
||||
NOTICE: drop cascades to 7 other objects
|
||||
DETAIL: drop cascades to type stats_import.complex_type
|
||||
|
||||
@@ -811,6 +811,14 @@ CREATE STATISTICS stats_import.test_stat
|
||||
ON name, comp, lower(arange), array_length(tags,1)
|
||||
FROM stats_import.test;
|
||||
|
||||
CREATE STATISTICS stats_import.test_stat_ndistinct (ndistinct)
|
||||
ON name, comp
|
||||
FROM stats_import.test;
|
||||
|
||||
CREATE STATISTICS stats_import.test_stat_dependencies (dependencies)
|
||||
ON name, comp
|
||||
FROM stats_import.test;
|
||||
|
||||
-- Generate statistics on table with data
|
||||
ANALYZE stats_import.test;
|
||||
|
||||
@@ -1137,4 +1145,101 @@ REVOKE MAINTAIN ON stats_import.test FROM regress_test_extstat_clear;
|
||||
REVOKE ALL ON SCHEMA stats_import FROM regress_test_extstat_clear;
|
||||
DROP ROLE regress_test_extstat_clear;
|
||||
|
||||
-- Tests for pg_restore_extended_stats().
|
||||
-- Invalid argument values.
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', NULL,
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', NULL,
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', NULL,
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', NULL,
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', NULL);
|
||||
-- Missing objects
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'schema_not_exist',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'table_not_exist',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'schema_not_exist',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test_clone',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'ext_stats_not_exist',
|
||||
'inherited', false);
|
||||
-- Incorrect relation/extended stats combination
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_clone',
|
||||
'inherited', false);
|
||||
|
||||
-- ndistinct value doesn't match object definition
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_ndistinct',
|
||||
'inherited', false,
|
||||
'n_distinct', '[{"attributes" : [1,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
-- Incorrect extended stats kind, ndistinct 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,
|
||||
'n_distinct', '[{"attributes" : [1,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
|
||||
-- ok: ndistinct
|
||||
SELECT pg_catalog.pg_restore_extended_stats(
|
||||
'schemaname', 'stats_import',
|
||||
'relname', 'test',
|
||||
'statistics_schemaname', 'stats_import',
|
||||
'statistics_name', 'test_stat_ndistinct',
|
||||
'inherited', false,
|
||||
'n_distinct', '[{"attributes" : [2,3], "ndistinct" : 4}]'::pg_ndistinct);
|
||||
|
||||
SELECT replace(e.n_distinct, '}, ', E'},\n') AS n_distinct
|
||||
FROM pg_stats_ext AS e
|
||||
WHERE e.statistics_schemaname = 'stats_import' AND
|
||||
e.statistics_name = 'test_stat_ndistinct' AND
|
||||
e.inherited = false;
|
||||
|
||||
DROP SCHEMA stats_import CASCADE;
|
||||
|
||||
@@ -2897,6 +2897,7 @@ SplitPoint
|
||||
SplitTextOutputData
|
||||
SplitVar
|
||||
StackElem
|
||||
StakindFlags
|
||||
StartDataPtrType
|
||||
StartLOPtrType
|
||||
StartLOsPtrType
|
||||
|
||||
Reference in New Issue
Block a user