Remove redundant pg_set_*_stats() variants.

After commit f3dae2ae58, the primary purpose of separating the
pg_set_*_stats() from the pg_restore_*_stats() variants was
eliminated.

Leave pg_restore_relation_stats() and pg_restore_attribute_stats(),
which satisfy both purposes, and remove pg_set_relation_stats() and
pg_set_attribute_stats().

Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/1457469.1740419458@sss.pgh.pa.us
This commit is contained in:
Jeff Davis 2025-02-25 16:15:47 -08:00
parent ecbff4378b
commit a5cbdeb98a
10 changed files with 823 additions and 1973 deletions

View File

@ -30181,41 +30181,72 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
<tbody> <tbody>
<row> <row>
<entry role="func_table_entry"> <entry role="func_table_entry"><para role="func_signature">
<para role="func_signature"> <indexterm>
<indexterm> <primary>pg_restore_relation_stats</primary>
<primary>pg_set_relation_stats</primary> </indexterm>
</indexterm> <function>pg_restore_relation_stats</function> (
<function>pg_set_relation_stats</function> ( <literal>VARIADIC</literal> <parameter>kwargs</parameter> <type>"any"</type> )
<parameter>relation</parameter> <type>regclass</type> <returnvalue>boolean</returnvalue>
<optional>, <parameter>relpages</parameter> <type>integer</type></optional> </para>
<optional>, <parameter>reltuples</parameter> <type>real</type></optional> <para>
<optional>, <parameter>relallvisible</parameter> <type>integer</type></optional> ) Updates table-level statistics. Ordinarily, these statistics are
<returnvalue>void</returnvalue> 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>
<para> <para>
Updates relation-level statistics for the given relation to the The tracked statistics may change from version to version, so
specified values. The parameters correspond to columns in <link arguments are passed as pairs of <replaceable>argname</replaceable>
linkend="catalog-pg-class"><structname>pg_class</structname></link>. Unspecified and <replaceable>argvalue</replaceable> in the form:
or <literal>NULL</literal> values leave the setting unchanged. <programlisting>
SELECT pg_restore_relation_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>
<para> <para>
Ordinarily, these statistics are collected automatically or updated For example, to set the <structname>relpages</structname> and
as a part of <xref linkend="sql-vacuum"/> or <xref <structname>reltuples</structname> of the table
linkend="sql-analyze"/>, so it's not necessary to call this <structname>mytable</structname>:
function. However, it may be useful when testing the effects of <programlisting>
statistics on the planner to understand or anticipate plan changes. SELECT pg_restore_relation_stats(
'relation', 'mytable'::regclass,
'relpages', 173::integer,
'reltuples', 10000::real);
</programlisting>
</para> </para>
<para> <para>
The caller must have the <literal>MAINTAIN</literal> privilege on The argument <literal>relation</literal> with a value of type
the table or be the owner of the database. <type>regclass</type> is required, and specifies the table. Other
arguments are the names of statistics corresponding to certain
columns in <link
linkend="catalog-pg-class"><structname>pg_class</structname></link>.
The currently-supported relation statistics are
<literal>relpages</literal> with a value of type
<type>integer</type>, <literal>reltuples</literal> with a value of
type <type>real</type>, and <literal>relallvisible</literal> with a
value of type <type>integer</type>.
</para> </para>
<para> <para>
The value of <structfield>relpages</structfield> must be greater than Additionally, this function supports argument name
or equal to <literal>-1</literal>, <literal>version</literal> of type <type>integer</type>, which
<structfield>reltuples</structfield> must be greater than or equal to specifies the version from which the statistics originated, improving
<literal>-1.0</literal>, and <structfield>relallvisible</structfield> interpretation of statistics from older versions of
must be greater than or equal to <literal>0</literal>. <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, return
<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> </para>
</entry> </entry>
</row> </row>
@ -30234,8 +30265,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
table was newly created. table was newly created.
</para> </para>
<para> <para>
The caller must have the <literal>MAINTAIN</literal> privilege on The caller must have the <literal>MAINTAIN</literal> privilege on the
the table or be the owner of the database. table or be the owner of the database.
</para> </para>
</entry> </entry>
</row> </row>
@ -30243,42 +30274,61 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
<row> <row>
<entry role="func_table_entry"><para role="func_signature"> <entry role="func_table_entry"><para role="func_signature">
<indexterm> <indexterm>
<primary>pg_restore_relation_stats</primary> <primary>pg_restore_attribute_stats</primary>
</indexterm> </indexterm>
<function>pg_restore_relation_stats</function> ( <function>pg_restore_attribute_stats</function> (
<literal>VARIADIC</literal> <parameter>kwargs</parameter> <type>"any"</type> ) <literal>VARIADIC</literal> <parameter>kwargs</parameter> <type>"any"</type> )
<returnvalue>boolean</returnvalue> <returnvalue>boolean</returnvalue>
</para>
<para>
Create or update column-level statistics. 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>
<para> <para>
Similar to <function>pg_set_relation_stats()</function>, but intended The tracked statistics may change from version to version, so
for bulk restore of relation statistics. The tracked statistics may arguments are passed as pairs of <replaceable>argname</replaceable>
change from version to version, so the primary purpose of this and <replaceable>argvalue</replaceable> in the form:
function is to maintain a consistent function signature to avoid <programlisting>
errors when restoring statistics from previous versions. SELECT pg_restore_attribute_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>
<para> <para>
Arguments are passed as pairs of <replaceable>argname</replaceable> For example, to set the <structname>avg_width</structname> and
and <replaceable>argvalue</replaceable>, where <structname>null_frac</structname> for the attribute
<replaceable>argname</replaceable> corresponds to a named argument in <structname>col1</structname> of the table
<function>pg_set_relation_stats()</function> and <structname>mytable</structname>:
<replaceable>argvalue</replaceable> is of the corresponding type. <programlisting>
SELECT pg_restore_attribute_stats(
'relation', 'mytable'::regclass,
'attname', 'col1'::name,
'inherited', false,
'avg_width', 125::integer,
'null_frac', 0.5::real);
</programlisting>
</para>
<para>
The required arguments are <literal>relation</literal> with a value
of type <type>regclass</type>, which specifies the table;
<literal>attname</literal> with a value of type <type>name</type>,
which specifies the column; and <literal>inherited</literal>, which
specifies whether the statistics includes values from child tables.
Other arguments are the names of statistics corresponding to columns
in <link
linkend="view-pg-stats"><structname>pg_stats</structname></link>.
</para> </para>
<para> <para>
Additionally, this function supports argument name Additionally, this function supports argument name
<literal>version</literal> of type <type>integer</type>, which <literal>version</literal> of type <type>integer</type>, which
specifies the version from which the statistics originated, improving specifies the version from which the statistics originated, improving
interpretation of older statistics. interpretation of statistics from older versions of
</para> <productname>PostgreSQL</productname>.
<para>
For example, to set the <structname>relpages</structname> and
<structname>reltuples</structname> of the table
<structname>mytable</structname>:
<programlisting>
SELECT pg_restore_relation_stats(
'relation', 'mytable'::regclass,
'relpages', 173::integer,
'reltuples', 10000::float4);
</programlisting>
</para> </para>
<para> <para>
Minor errors are reported as a <literal>WARNING</literal> and Minor errors are reported as a <literal>WARNING</literal> and
@ -30286,53 +30336,9 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
specified statistics are successfully restored, return specified statistics are successfully restored, return
<literal>true</literal>, otherwise <literal>false</literal>. <literal>true</literal>, otherwise <literal>false</literal>.
</para> </para>
</entry>
</row>
<row>
<entry role="func_table_entry">
<para role="func_signature">
<indexterm>
<primary>pg_set_attribute_stats</primary>
</indexterm>
<function>pg_set_attribute_stats</function> (
<parameter>relation</parameter> <type>regclass</type>,
<parameter>attname</parameter> <type>name</type>,
<parameter>inherited</parameter> <type>boolean</type>
<optional>, <parameter>null_frac</parameter> <type>real</type></optional>
<optional>, <parameter>avg_width</parameter> <type>integer</type></optional>
<optional>, <parameter>n_distinct</parameter> <type>real</type></optional>
<optional>, <parameter>most_common_vals</parameter> <type>text</type>, <parameter>most_common_freqs</parameter> <type>real[]</type> </optional>
<optional>, <parameter>histogram_bounds</parameter> <type>text</type> </optional>
<optional>, <parameter>correlation</parameter> <type>real</type> </optional>
<optional>, <parameter>most_common_elems</parameter> <type>text</type>, <parameter>most_common_elem_freqs</parameter> <type>real[]</type> </optional>
<optional>, <parameter>elem_count_histogram</parameter> <type>real[]</type> </optional>
<optional>, <parameter>range_length_histogram</parameter> <type>text</type> </optional>
<optional>, <parameter>range_empty_frac</parameter> <type>real</type> </optional>
<optional>, <parameter>range_bounds_histogram</parameter> <type>text</type> </optional> )
<returnvalue>void</returnvalue>
</para>
<para> <para>
Creates or updates attribute-level statistics for the given relation The caller must have the <literal>MAINTAIN</literal> privilege on the
and attribute name to the specified values. The parameters correspond table or be the owner of the database.
to attributes of the same name found in the <link
linkend="view-pg-stats"><structname>pg_stats</structname></link>
view.
</para>
<para>
Optional parameters default to <literal>NULL</literal>, which leave
the corresponding statistic unchanged.
</para>
<para>
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 may be useful when testing the effects of
statistics on the planner to understand or anticipate plan changes.
</para>
<para>
The caller must have the <literal>MAINTAIN</literal> privilege on
the table or be the owner of the database.
</para> </para>
</entry> </entry>
</row> </row>
@ -30350,8 +30356,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
<returnvalue>void</returnvalue> <returnvalue>void</returnvalue>
</para> </para>
<para> <para>
Clears table-level statistics for the given relation attribute, as Clears column-level statistics for the given relation and
though the table was newly created. attribute, as though the table was newly created.
</para> </para>
<para> <para>
The caller must have the <literal>MAINTAIN</literal> privilege on The caller must have the <literal>MAINTAIN</literal> privilege on
@ -30359,58 +30365,6 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
</para> </para>
</entry> </entry>
</row> </row>
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
<primary>pg_restore_attribute_stats</primary>
</indexterm>
<function>pg_restore_attribute_stats</function> (
<literal>VARIADIC</literal> <parameter>kwargs</parameter> <type>"any"</type> )
<returnvalue>boolean</returnvalue>
</para>
<para>
Similar to <function>pg_set_attribute_stats()</function>, but
intended for bulk restore of attribute statistics. The tracked
statistics may change from version to version, so the primary purpose
of this function is to maintain a consistent function signature to
avoid errors when restoring statistics from previous versions.
</para>
<para>
Arguments are passed as pairs of <replaceable>argname</replaceable>
and <replaceable>argvalue</replaceable>, where
<replaceable>argname</replaceable> corresponds to a named argument in
<function>pg_set_attribute_stats()</function> and
<replaceable>argvalue</replaceable> is of the corresponding type.
</para>
<para>
Additionally, this function supports argument name
<literal>version</literal> of type <type>integer</type>, which
specifies the version from which the statistics originated, improving
interpretation of older statistics.
</para>
<para>
For example, to set the <structname>avg_width</structname> and
<structname>null_frac</structname> for the attribute
<structname>col1</structname> of the table
<structname>mytable</structname>:
<programlisting>
SELECT pg_restore_attribute_stats(
'relation', 'mytable'::regclass,
'attname', 'col1'::name,
'inherited', false,
'avg_width', 125::integer,
'null_frac', 0.5::real);
</programlisting>
</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, return
<literal>true</literal>, otherwise <literal>false</literal>.
</para>
</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>

View File

@ -636,38 +636,6 @@ LANGUAGE INTERNAL
CALLED ON NULL INPUT VOLATILE PARALLEL SAFE CALLED ON NULL INPUT VOLATILE PARALLEL SAFE
AS 'pg_stat_reset_slru'; AS 'pg_stat_reset_slru';
CREATE OR REPLACE FUNCTION
pg_set_relation_stats(relation regclass,
relpages integer DEFAULT NULL,
reltuples real DEFAULT NULL,
relallvisible integer DEFAULT NULL)
RETURNS void
LANGUAGE INTERNAL
CALLED ON NULL INPUT VOLATILE
AS 'pg_set_relation_stats';
CREATE OR REPLACE FUNCTION
pg_set_attribute_stats(relation regclass,
attname name,
inherited bool,
null_frac real DEFAULT NULL,
avg_width integer DEFAULT NULL,
n_distinct real DEFAULT NULL,
most_common_vals text DEFAULT NULL,
most_common_freqs real[] DEFAULT NULL,
histogram_bounds text DEFAULT NULL,
correlation real DEFAULT NULL,
most_common_elems text DEFAULT NULL,
most_common_elem_freqs real[] DEFAULT NULL,
elem_count_histogram real[] DEFAULT NULL,
range_length_histogram text DEFAULT NULL,
range_empty_frac real DEFAULT NULL,
range_bounds_histogram text DEFAULT NULL)
RETURNS void
LANGUAGE INTERNAL
CALLED ON NULL INPUT VOLATILE
AS 'pg_set_attribute_stats';
-- --
-- The default permissions for functions mean that anyone can execute them. -- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather -- A number of functions shouldn't be executable by just anyone, but rather

View File

@ -76,16 +76,16 @@ static struct StatsArgInfo attarginfo[] =
[NUM_ATTRIBUTE_STATS_ARGS] = {0} [NUM_ATTRIBUTE_STATS_ARGS] = {0}
}; };
static bool attribute_statistics_update(FunctionCallInfo fcinfo, int elevel); static bool attribute_statistics_update(FunctionCallInfo fcinfo);
static Node *get_attr_expr(Relation rel, int attnum); static Node *get_attr_expr(Relation rel, int attnum);
static void get_attr_stat_type(Oid reloid, AttrNumber attnum, int elevel, static void get_attr_stat_type(Oid reloid, AttrNumber attnum,
Oid *atttypid, int32 *atttypmod, Oid *atttypid, int32 *atttypmod,
char *atttyptype, Oid *atttypcoll, char *atttyptype, Oid *atttypcoll,
Oid *eq_opr, Oid *lt_opr); Oid *eq_opr, Oid *lt_opr);
static bool get_elem_stat_type(Oid atttypid, char atttyptype, int elevel, static bool get_elem_stat_type(Oid atttypid, char atttyptype,
Oid *elemtypid, Oid *elem_eq_opr); Oid *elemtypid, Oid *elem_eq_opr);
static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d,
Oid typid, int32 typmod, int elevel, bool *ok); Oid typid, int32 typmod, bool *ok);
static void set_stats_slot(Datum *values, bool *nulls, bool *replaces, static void set_stats_slot(Datum *values, bool *nulls, bool *replaces,
int16 stakind, Oid staop, Oid stacoll, int16 stakind, Oid staop, Oid stacoll,
Datum stanumbers, bool stanumbers_isnull, Datum stanumbers, bool stanumbers_isnull,
@ -109,11 +109,11 @@ static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
* *
* Major errors, such as the table not existing, the attribute not existing, * Major errors, such as the table not existing, the attribute not existing,
* or a permissions failure are always reported at ERROR. Other errors, such * or a permissions failure are always reported at ERROR. Other errors, such
* as a conversion failure on one statistic kind, are reported at 'elevel', * as a conversion failure on one statistic kind, are reported as a WARNING
* and other statistic kinds may still be updated. * and other statistic kinds may still be updated.
*/ */
static bool static bool
attribute_statistics_update(FunctionCallInfo fcinfo, int elevel) attribute_statistics_update(FunctionCallInfo fcinfo)
{ {
Oid reloid; Oid reloid;
Name attname; Name attname;
@ -184,33 +184,29 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
inherited = PG_GETARG_BOOL(INHERITED_ARG); inherited = PG_GETARG_BOOL(INHERITED_ARG);
/* /*
* Check argument sanity. If some arguments are unusable, emit at elevel * Check argument sanity. If some arguments are unusable, emit a WARNING
* and set the corresponding argument to NULL in fcinfo. * and set the corresponding argument to NULL in fcinfo.
*/ */
if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_FREQS_ARG, if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_FREQS_ARG))
elevel))
{ {
do_mcv = false; do_mcv = false;
result = false; result = false;
} }
if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_ELEM_FREQS_ARG, if (!stats_check_arg_array(fcinfo, attarginfo, MOST_COMMON_ELEM_FREQS_ARG))
elevel))
{ {
do_mcelem = false; do_mcelem = false;
result = false; result = false;
} }
if (!stats_check_arg_array(fcinfo, attarginfo, ELEM_COUNT_HISTOGRAM_ARG, if (!stats_check_arg_array(fcinfo, attarginfo, ELEM_COUNT_HISTOGRAM_ARG))
elevel))
{ {
do_dechist = false; do_dechist = false;
result = false; result = false;
} }
if (!stats_check_arg_pair(fcinfo, attarginfo, if (!stats_check_arg_pair(fcinfo, attarginfo,
MOST_COMMON_VALS_ARG, MOST_COMMON_FREQS_ARG, MOST_COMMON_VALS_ARG, MOST_COMMON_FREQS_ARG))
elevel))
{ {
do_mcv = false; do_mcv = false;
result = false; result = false;
@ -218,7 +214,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
if (!stats_check_arg_pair(fcinfo, attarginfo, if (!stats_check_arg_pair(fcinfo, attarginfo,
MOST_COMMON_ELEMS_ARG, MOST_COMMON_ELEMS_ARG,
MOST_COMMON_ELEM_FREQS_ARG, elevel)) MOST_COMMON_ELEM_FREQS_ARG))
{ {
do_mcelem = false; do_mcelem = false;
result = false; result = false;
@ -226,14 +222,14 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
if (!stats_check_arg_pair(fcinfo, attarginfo, if (!stats_check_arg_pair(fcinfo, attarginfo,
RANGE_LENGTH_HISTOGRAM_ARG, RANGE_LENGTH_HISTOGRAM_ARG,
RANGE_EMPTY_FRAC_ARG, elevel)) RANGE_EMPTY_FRAC_ARG))
{ {
do_range_length_histogram = false; do_range_length_histogram = false;
result = false; result = false;
} }
/* derive information from attribute */ /* derive information from attribute */
get_attr_stat_type(reloid, attnum, elevel, get_attr_stat_type(reloid, attnum,
&atttypid, &atttypmod, &atttypid, &atttypmod,
&atttyptype, &atttypcoll, &atttyptype, &atttypcoll,
&eq_opr, &lt_opr); &eq_opr, &lt_opr);
@ -241,10 +237,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
/* if needed, derive element type */ /* if needed, derive element type */
if (do_mcelem || do_dechist) if (do_mcelem || do_dechist)
{ {
if (!get_elem_stat_type(atttypid, atttyptype, elevel, if (!get_elem_stat_type(atttypid, atttyptype,
&elemtypid, &elem_eq_opr)) &elemtypid, &elem_eq_opr))
{ {
ereport(elevel, ereport(WARNING,
(errmsg("unable to determine element type of attribute \"%s\"", NameStr(*attname)), (errmsg("unable to determine element type of attribute \"%s\"", NameStr(*attname)),
errdetail("Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST."))); errdetail("Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST.")));
elemtypid = InvalidOid; elemtypid = InvalidOid;
@ -259,7 +255,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
/* histogram and correlation require less-than operator */ /* histogram and correlation require less-than operator */
if ((do_histogram || do_correlation) && !OidIsValid(lt_opr)) if ((do_histogram || do_correlation) && !OidIsValid(lt_opr))
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine less-than operator for attribute \"%s\"", NameStr(*attname)), errmsg("could not determine less-than operator for attribute \"%s\"", NameStr(*attname)),
errdetail("Cannot set STATISTIC_KIND_HISTOGRAM or STATISTIC_KIND_CORRELATION."))); errdetail("Cannot set STATISTIC_KIND_HISTOGRAM or STATISTIC_KIND_CORRELATION.")));
@ -273,7 +269,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
if ((do_range_length_histogram || do_bounds_histogram) && if ((do_range_length_histogram || do_bounds_histogram) &&
!(atttyptype == TYPTYPE_RANGE || atttyptype == TYPTYPE_MULTIRANGE)) !(atttyptype == TYPTYPE_RANGE || atttyptype == TYPTYPE_MULTIRANGE))
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("attribute \"%s\" is not a range type", NameStr(*attname)), errmsg("attribute \"%s\" is not a range type", NameStr(*attname)),
errdetail("Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM."))); errdetail("Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM.")));
@ -322,7 +318,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
&array_in_fn, &array_in_fn,
PG_GETARG_DATUM(MOST_COMMON_VALS_ARG), PG_GETARG_DATUM(MOST_COMMON_VALS_ARG),
atttypid, atttypmod, atttypid, atttypmod,
elevel, &converted); &converted);
if (converted) if (converted)
{ {
@ -344,7 +340,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
stavalues = text_to_stavalues("histogram_bounds", stavalues = text_to_stavalues("histogram_bounds",
&array_in_fn, &array_in_fn,
PG_GETARG_DATUM(HISTOGRAM_BOUNDS_ARG), PG_GETARG_DATUM(HISTOGRAM_BOUNDS_ARG),
atttypid, atttypmod, elevel, atttypid, atttypmod,
&converted); &converted);
if (converted) if (converted)
@ -382,7 +378,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
&array_in_fn, &array_in_fn,
PG_GETARG_DATUM(MOST_COMMON_ELEMS_ARG), PG_GETARG_DATUM(MOST_COMMON_ELEMS_ARG),
elemtypid, atttypmod, elemtypid, atttypmod,
elevel, &converted); &converted);
if (converted) if (converted)
{ {
@ -422,7 +418,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
&array_in_fn, &array_in_fn,
PG_GETARG_DATUM(RANGE_BOUNDS_HISTOGRAM_ARG), PG_GETARG_DATUM(RANGE_BOUNDS_HISTOGRAM_ARG),
atttypid, atttypmod, atttypid, atttypmod,
elevel, &converted); &converted);
if (converted) if (converted)
{ {
@ -449,7 +445,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo, int elevel)
stavalues = text_to_stavalues("range_length_histogram", stavalues = text_to_stavalues("range_length_histogram",
&array_in_fn, &array_in_fn,
PG_GETARG_DATUM(RANGE_LENGTH_HISTOGRAM_ARG), PG_GETARG_DATUM(RANGE_LENGTH_HISTOGRAM_ARG),
FLOAT8OID, 0, elevel, &converted); FLOAT8OID, 0, &converted);
if (converted) if (converted)
{ {
@ -517,7 +513,7 @@ get_attr_expr(Relation rel, int attnum)
* Derive type information from the attribute. * Derive type information from the attribute.
*/ */
static void static void
get_attr_stat_type(Oid reloid, AttrNumber attnum, int elevel, get_attr_stat_type(Oid reloid, AttrNumber attnum,
Oid *atttypid, int32 *atttypmod, Oid *atttypid, int32 *atttypmod,
char *atttyptype, Oid *atttypcoll, char *atttyptype, Oid *atttypcoll,
Oid *eq_opr, Oid *lt_opr) Oid *eq_opr, Oid *lt_opr)
@ -599,7 +595,7 @@ get_attr_stat_type(Oid reloid, AttrNumber attnum, int elevel,
* Derive element type information from the attribute type. * Derive element type information from the attribute type.
*/ */
static bool static bool
get_elem_stat_type(Oid atttypid, char atttyptype, int elevel, get_elem_stat_type(Oid atttypid, char atttyptype,
Oid *elemtypid, Oid *elem_eq_opr) Oid *elemtypid, Oid *elem_eq_opr)
{ {
TypeCacheEntry *elemtypcache; TypeCacheEntry *elemtypcache;
@ -634,13 +630,13 @@ get_elem_stat_type(Oid atttypid, char atttyptype, int elevel,
/* /*
* Cast a text datum into an array with element type elemtypid. * Cast a text datum into an array with element type elemtypid.
* *
* If an error is encountered, capture it and re-throw at elevel, and set ok * If an error is encountered, capture it and re-throw a WARNING, and set ok
* to false. If the resulting array contains NULLs, raise an error at elevel * to false. If the resulting array contains NULLs, raise a WARNING and set ok
* and set ok to false. Otherwise, set ok to true. * to false. Otherwise, set ok to true.
*/ */
static Datum static Datum
text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
int32 typmod, int elevel, bool *ok) int32 typmod, bool *ok)
{ {
LOCAL_FCINFO(fcinfo, 8); LOCAL_FCINFO(fcinfo, 8);
char *s; char *s;
@ -667,8 +663,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
if (escontext.error_occurred) if (escontext.error_occurred)
{ {
if (elevel != ERROR) escontext.error_data->elevel = WARNING;
escontext.error_data->elevel = elevel;
ThrowErrorData(escontext.error_data); ThrowErrorData(escontext.error_data);
*ok = false; *ok = false;
return (Datum) 0; return (Datum) 0;
@ -676,7 +671,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
if (array_contains_nulls(DatumGetArrayTypeP(result))) if (array_contains_nulls(DatumGetArrayTypeP(result)))
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" array cannot contain NULL values", staname))); errmsg("\"%s\" array cannot contain NULL values", staname)));
*ok = false; *ok = false;
@ -851,33 +846,6 @@ init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
} }
} }
/*
* Import statistics for a given relation attribute.
*
* Inserts or replaces a row in pg_statistic for the given relation and
* attribute name. It takes input parameters that correspond to columns in the
* view pg_stats.
*
* Parameters null_frac, avg_width, and n_distinct all correspond to NOT NULL
* columns in pg_statistic. The remaining parameters all belong to a specific
* stakind. Some stakinds require multiple parameters, which must be specified
* together (or neither specified).
*
* Parameters are only superficially validated. Omitting a parameter or
* passing NULL leaves the statistic unchanged.
*
* Parameters corresponding to ANYARRAY columns are instead passed in as text
* values, which is a valid input string for an array of the type or element
* type of the attribute. Any error generated by the array_in() function will
* in turn fail the function.
*/
Datum
pg_set_attribute_stats(PG_FUNCTION_ARGS)
{
attribute_statistics_update(fcinfo, ERROR);
PG_RETURN_VOID();
}
/* /*
* Delete statistics for the given attribute. * Delete statistics for the given attribute.
*/ */
@ -933,10 +901,10 @@ pg_restore_attribute_stats(PG_FUNCTION_ARGS)
InvalidOid, NULL, NULL); InvalidOid, NULL, NULL);
if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo, if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
attarginfo, WARNING)) attarginfo))
result = false; result = false;
if (!attribute_statistics_update(positional_fcinfo, WARNING)) if (!attribute_statistics_update(positional_fcinfo))
result = false; result = false;
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);

View File

@ -48,13 +48,13 @@ static struct StatsArgInfo relarginfo[] =
[NUM_RELATION_STATS_ARGS] = {0} [NUM_RELATION_STATS_ARGS] = {0}
}; };
static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel); static bool relation_statistics_update(FunctionCallInfo fcinfo);
/* /*
* Internal function for modifying statistics for a relation. * Internal function for modifying statistics for a relation.
*/ */
static bool static bool
relation_statistics_update(FunctionCallInfo fcinfo, int elevel) relation_statistics_update(FunctionCallInfo fcinfo)
{ {
bool result = true; bool result = true;
Oid reloid; Oid reloid;
@ -83,7 +83,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG); reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG);
if (reltuples < -1.0) if (reltuples < -1.0)
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("reltuples cannot be < -1.0"))); errmsg("reltuples cannot be < -1.0")));
result = false; result = false;
@ -118,7 +118,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
ctup = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid)); ctup = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid));
if (!HeapTupleIsValid(ctup)) if (!HeapTupleIsValid(ctup))
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_OBJECT_IN_USE), (errcode(ERRCODE_OBJECT_IN_USE),
errmsg("pg_class entry for relid %u not found", reloid))); errmsg("pg_class entry for relid %u not found", reloid)));
table_close(crel, RowExclusiveLock); table_close(crel, RowExclusiveLock);
@ -169,16 +169,6 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
return result; return result;
} }
/*
* Set statistics for a given pg_class entry.
*/
Datum
pg_set_relation_stats(PG_FUNCTION_ARGS)
{
relation_statistics_update(fcinfo, ERROR);
PG_RETURN_VOID();
}
/* /*
* Clear statistics for a given pg_class entry; that is, set back to initial * Clear statistics for a given pg_class entry; that is, set back to initial
* stats for a newly-created table. * stats for a newly-created table.
@ -199,7 +189,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
newfcinfo->args[3].value = UInt32GetDatum(0); newfcinfo->args[3].value = UInt32GetDatum(0);
newfcinfo->args[3].isnull = false; newfcinfo->args[3].isnull = false;
relation_statistics_update(newfcinfo, ERROR); relation_statistics_update(newfcinfo);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
@ -214,10 +204,10 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
InvalidOid, NULL, NULL); InvalidOid, NULL, NULL);
if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo, if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
relarginfo, WARNING)) relarginfo))
result = false; result = false;
if (!relation_statistics_update(positional_fcinfo, WARNING)) if (!relation_statistics_update(positional_fcinfo))
result = false; result = false;
PG_RETURN_BOOL(result); PG_RETURN_BOOL(result);

View File

@ -48,13 +48,13 @@ stats_check_required_arg(FunctionCallInfo fcinfo,
* Check that argument is either NULL or a one dimensional array with no * Check that argument is either NULL or a one dimensional array with no
* NULLs. * NULLs.
* *
* If a problem is found, emit at elevel, and return false. Otherwise return * If a problem is found, emit a WARNING, and return false. Otherwise return
* true. * true.
*/ */
bool bool
stats_check_arg_array(FunctionCallInfo fcinfo, stats_check_arg_array(FunctionCallInfo fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo,
int argnum, int elevel) int argnum)
{ {
ArrayType *arr; ArrayType *arr;
@ -65,7 +65,7 @@ stats_check_arg_array(FunctionCallInfo fcinfo,
if (ARR_NDIM(arr) != 1) if (ARR_NDIM(arr) != 1)
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" cannot be a multidimensional array", errmsg("\"%s\" cannot be a multidimensional array",
arginfo[argnum].argname))); arginfo[argnum].argname)));
@ -74,7 +74,7 @@ stats_check_arg_array(FunctionCallInfo fcinfo,
if (array_contains_nulls(arr)) if (array_contains_nulls(arr))
{ {
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" array cannot contain NULL values", errmsg("\"%s\" array cannot contain NULL values",
arginfo[argnum].argname))); arginfo[argnum].argname)));
@ -89,13 +89,13 @@ stats_check_arg_array(FunctionCallInfo fcinfo,
* a particular stakind, such as most_common_vals and most_common_freqs for * a particular stakind, such as most_common_vals and most_common_freqs for
* STATISTIC_KIND_MCV. * STATISTIC_KIND_MCV.
* *
* If a problem is found, emit at elevel, and return false. Otherwise return * If a problem is found, emit a WARNING, and return false. Otherwise return
* true. * true.
*/ */
bool bool
stats_check_arg_pair(FunctionCallInfo fcinfo, stats_check_arg_pair(FunctionCallInfo fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo,
int argnum1, int argnum2, int elevel) int argnum1, int argnum2)
{ {
if (PG_ARGISNULL(argnum1) && PG_ARGISNULL(argnum2)) if (PG_ARGISNULL(argnum1) && PG_ARGISNULL(argnum2))
return true; return true;
@ -105,7 +105,7 @@ stats_check_arg_pair(FunctionCallInfo fcinfo,
int nullarg = PG_ARGISNULL(argnum1) ? argnum1 : argnum2; int nullarg = PG_ARGISNULL(argnum1) ? argnum1 : argnum2;
int otherarg = PG_ARGISNULL(argnum1) ? argnum2 : argnum1; int otherarg = PG_ARGISNULL(argnum1) ? argnum2 : argnum1;
ereport(elevel, ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" must be specified when \"%s\" is specified", errmsg("\"%s\" must be specified when \"%s\" is specified",
arginfo[nullarg].argname, arginfo[nullarg].argname,
@ -216,7 +216,7 @@ stats_lock_check_privileges(Oid reloid)
* found. * found.
*/ */
static int static int
get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel) get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo)
{ {
int argnum; int argnum;
@ -224,7 +224,7 @@ get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel)
if (pg_strcasecmp(argname, arginfo[argnum].argname) == 0) if (pg_strcasecmp(argname, arginfo[argnum].argname) == 0)
return argnum; return argnum;
ereport(elevel, ereport(WARNING,
(errmsg("unrecognized argument name: \"%s\"", argname))); (errmsg("unrecognized argument name: \"%s\"", argname)));
return -1; return -1;
@ -234,11 +234,11 @@ get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo, int elevel)
* Ensure that a given argument matched the expected type. * Ensure that a given argument matched the expected type.
*/ */
static bool static bool
stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype, int elevel) stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype)
{ {
if (argtype != expectedtype) if (argtype != expectedtype)
{ {
ereport(elevel, ereport(WARNING,
(errmsg("argument \"%s\" has type \"%s\", expected type \"%s\"", (errmsg("argument \"%s\" has type \"%s\", expected type \"%s\"",
argname, format_type_be(argtype), argname, format_type_be(argtype),
format_type_be(expectedtype)))); format_type_be(expectedtype))));
@ -260,8 +260,7 @@ stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype, int ele
bool bool
stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo,
FunctionCallInfo positional_fcinfo, FunctionCallInfo positional_fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo)
int elevel)
{ {
Datum *args; Datum *args;
bool *argnulls; bool *argnulls;
@ -319,11 +318,10 @@ stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo,
if (pg_strcasecmp(argname, "version") == 0) if (pg_strcasecmp(argname, "version") == 0)
continue; continue;
argnum = get_arg_by_name(argname, arginfo, elevel); argnum = get_arg_by_name(argname, arginfo);
if (argnum < 0 || !stats_check_arg_type(argname, types[i + 1], if (argnum < 0 || !stats_check_arg_type(argname, types[i + 1],
arginfo[argnum].argtype, arginfo[argnum].argtype))
elevel))
{ {
result = false; result = false;
continue; continue;

View File

@ -57,6 +57,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 202502241 #define CATALOG_VERSION_NO 202502242
#endif #endif

View File

@ -1,4 +1,4 @@
#---------------------------------------------------------------------- \#----------------------------------------------------------------------
# #
# pg_proc.dat # pg_proc.dat
# Initial contents of the pg_proc system catalog. # Initial contents of the pg_proc system catalog.
@ -12420,7 +12420,14 @@
proargnames => '{kwargs}', proargnames => '{kwargs}',
proargmodes => '{v}', proargmodes => '{v}',
prosrc => 'pg_restore_relation_stats' }, prosrc => 'pg_restore_relation_stats' },
{ oid => '8460', { oid => '9160',
descr => 'clear statistics on relation',
proname => 'pg_clear_relation_stats', provolatile => 'v', proisstrict => 'f',
proparallel => 'u', prorettype => 'void',
proargtypes => 'regclass',
proargnames => '{relation}',
prosrc => 'pg_clear_relation_stats' },
{ oid => '8461',
descr => 'restore statistics on attribute', descr => 'restore statistics on attribute',
proname => 'pg_restore_attribute_stats', provolatile => 'v', proisstrict => 'f', proname => 'pg_restore_attribute_stats', provolatile => 'v', proisstrict => 'f',
provariadic => 'any', provariadic => 'any',
@ -12430,33 +12437,12 @@
proargmodes => '{v}', proargmodes => '{v}',
prosrc => 'pg_restore_attribute_stats' }, prosrc => 'pg_restore_attribute_stats' },
{ oid => '9162', { oid => '9162',
descr => 'set statistics on attribute',
proname => 'pg_set_attribute_stats', provolatile => 'v', proisstrict => 'f',
proparallel => 'u', prorettype => 'void',
proargtypes => 'regclass name bool float4 int4 float4 text _float4 text float4 text _float4 _float4 text float4 text',
proargnames => '{relation,attname,inherited,null_frac,avg_width,n_distinct,most_common_vals,most_common_freqs,histogram_bounds,correlation,most_common_elems,most_common_elem_freqs,elem_count_histogram,range_length_histogram,range_empty_frac,range_bounds_histogram}',
prosrc => 'pg_set_attribute_stats' },
{ oid => '9163',
descr => 'clear statistics on attribute', descr => 'clear statistics on attribute',
proname => 'pg_clear_attribute_stats', provolatile => 'v', proisstrict => 'f', proname => 'pg_clear_attribute_stats', provolatile => 'v', proisstrict => 'f',
proparallel => 'u', prorettype => 'void', proparallel => 'u', prorettype => 'void',
proargtypes => 'regclass name bool', proargtypes => 'regclass name bool',
proargnames => '{relation,attname,inherited}', proargnames => '{relation,attname,inherited}',
prosrc => 'pg_clear_attribute_stats' }, prosrc => 'pg_clear_attribute_stats' },
{ oid => '9944',
descr => 'set statistics on relation',
proname => 'pg_set_relation_stats', provolatile => 'v', proisstrict => 'f',
proparallel => 'u', prorettype => 'void',
proargtypes => 'regclass int4 float4 int4',
proargnames => '{relation,relpages,reltuples,relallvisible}',
prosrc => 'pg_set_relation_stats' },
{ oid => '9945',
descr => 'clear statistics on relation',
proname => 'pg_clear_relation_stats', provolatile => 'v', proisstrict => 'f',
proparallel => 'u', prorettype => 'void',
proargtypes => 'regclass',
proargnames => '{relation}',
prosrc => 'pg_clear_relation_stats' },
# GiST stratnum implementations # GiST stratnum implementations
{ oid => '8047', descr => 'GiST support', { oid => '8047', descr => 'GiST support',

View File

@ -25,17 +25,15 @@ extern void stats_check_required_arg(FunctionCallInfo fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo,
int argnum); int argnum);
extern bool stats_check_arg_array(FunctionCallInfo fcinfo, extern bool stats_check_arg_array(FunctionCallInfo fcinfo,
struct StatsArgInfo *arginfo, int argnum, struct StatsArgInfo *arginfo, int argnum);
int elevel);
extern bool stats_check_arg_pair(FunctionCallInfo fcinfo, extern bool stats_check_arg_pair(FunctionCallInfo fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo,
int argnum1, int argnum2, int elevel); int argnum1, int argnum2);
extern void stats_lock_check_privileges(Oid reloid); extern void stats_lock_check_privileges(Oid reloid);
extern bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, extern bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo,
FunctionCallInfo positional_fcinfo, FunctionCallInfo positional_fcinfo,
struct StatsArgInfo *arginfo, struct StatsArgInfo *arginfo);
int elevel);
#endif /* STATS_UTILS_H */ #endif /* STATS_UTILS_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff