Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 40e27d0

Browse files
committed
Use attnum to identify index columns in pg_restore_attribute_stats().
Previously we used attname for both table and index columns, but that is problematic for indexes because their attnames are assigned by internal rules that don't guarantee to preserve the names across dump and reload. (This is what's causing the remaining buildfarm failures in cross-version-upgrade tests.) Fortunately we can use attnum instead, since there's no such thing as adding or dropping columns in an existing index. We met this same problem previously with ALTER INDEX ... SET STATISTICS, and solved it the same way, cf commit 5b6d13e. In pg_restore_attribute_stats() itself, we accept either attnum or attname, but the policy used by pg_dump is to always use attname for tables and attnum for indexes. Author: Tom Lane <tgl@sss.pgh.pa.us> Author: Corey Huinker <corey.huinker@gmail.com> Discussion: https://postgr.es/m/1457469.1740419458@sss.pgh.pa.us
1 parent f734c9f commit 40e27d0

File tree

8 files changed

+391
-157
lines changed

8 files changed

+391
-157
lines changed

doc/src/sgml/func.sgml

+24-23
Original file line numberDiff line numberDiff line change
@@ -30209,8 +30209,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3020930209
</programlisting>
3021030210
</para>
3021130211
<para>
30212-
For example, to set the <structname>relpages</structname> and
30213-
<structname>reltuples</structname> of the table
30212+
For example, to set the <structfield>relpages</structfield> and
30213+
<structfield>reltuples</structfield> values for the table
3021430214
<structname>mytable</structname>:
3021530215
<programlisting>
3021630216
SELECT pg_restore_relation_stats(
@@ -30222,8 +30222,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3022230222
<para>
3022330223
The argument <literal>relation</literal> with a value of type
3022430224
<type>regclass</type> is required, and specifies the table. Other
30225-
arguments are the names of statistics corresponding to certain
30226-
columns in <link
30225+
arguments are the names and values of statistics corresponding to
30226+
certain columns in <link
3022730227
linkend="catalog-pg-class"><structname>pg_class</structname></link>.
3022830228
The currently-supported relation statistics are
3022930229
<literal>relpages</literal> with a value of type
@@ -30232,16 +30232,16 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3023230232
value of type <type>integer</type>.
3023330233
</para>
3023430234
<para>
30235-
Additionally, this function supports argument name
30235+
Additionally, this function accepts argument name
3023630236
<literal>version</literal> of type <type>integer</type>, which
30237-
specifies the version from which the statistics originated, improving
30238-
interpretation of statistics from older versions of
30239-
<productname>PostgreSQL</productname>.
30237+
specifies the server version from which the statistics originated.
30238+
This is anticipated to be helpful in porting statistics from older
30239+
versions of <productname>PostgreSQL</productname>.
3024030240
</para>
3024130241
<para>
3024230242
Minor errors are reported as a <literal>WARNING</literal> and
3024330243
ignored, and remaining statistics will still be restored. If all
30244-
specified statistics are successfully restored, return
30244+
specified statistics are successfully restored, returns
3024530245
<literal>true</literal>, otherwise <literal>false</literal>.
3024630246
</para>
3024730247
<para>
@@ -30281,7 +30281,7 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3028130281
<returnvalue>boolean</returnvalue>
3028230282
</para>
3028330283
<para>
30284-
Create or update column-level statistics. Ordinarily, these
30284+
Creates or updates column-level statistics. Ordinarily, these
3028530285
statistics are collected automatically or updated as a part of <xref
3028630286
linkend="sql-vacuum"/> or <xref linkend="sql-analyze"/>, so it's not
3028730287
necessary to call this function. However, it is useful after a
@@ -30300,9 +30300,9 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3030030300
</programlisting>
3030130301
</para>
3030230302
<para>
30303-
For example, to set the <structname>avg_width</structname> and
30304-
<structname>null_frac</structname> for the attribute
30305-
<structname>col1</structname> of the table
30303+
For example, to set the <structfield>avg_width</structfield> and
30304+
<structfield>null_frac</structfield> values for the attribute
30305+
<structfield>col1</structfield> of the table
3030630306
<structname>mytable</structname>:
3030730307
<programlisting>
3030830308
SELECT pg_restore_attribute_stats(
@@ -30315,25 +30315,26 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3031530315
</para>
3031630316
<para>
3031730317
The required arguments are <literal>relation</literal> with a value
30318-
of type <type>regclass</type>, which specifies the table;
30319-
<literal>attname</literal> with a value of type <type>name</type>,
30318+
of type <type>regclass</type>, which specifies the table; either
30319+
<literal>attname</literal> with a value of type <type>name</type> or
30320+
<literal>attnum</literal> with a value of type <type>smallint</type>,
3032030321
which specifies the column; and <literal>inherited</literal>, which
30321-
specifies whether the statistics includes values from child tables.
30322-
Other arguments are the names of statistics corresponding to columns
30323-
in <link
30322+
specifies whether the statistics include values from child tables.
30323+
Other arguments are the names and values of statistics corresponding
30324+
to columns in <link
3032430325
linkend="view-pg-stats"><structname>pg_stats</structname></link>.
3032530326
</para>
3032630327
<para>
30327-
Additionally, this function supports argument name
30328+
Additionally, this function accepts argument name
3032830329
<literal>version</literal> of type <type>integer</type>, which
30329-
specifies the version from which the statistics originated, improving
30330-
interpretation of statistics from older versions of
30331-
<productname>PostgreSQL</productname>.
30330+
specifies the server version from which the statistics originated.
30331+
This is anticipated to be helpful in porting statistics from older
30332+
versions of <productname>PostgreSQL</productname>.
3033230333
</para>
3033330334
<para>
3033430335
Minor errors are reported as a <literal>WARNING</literal> and
3033530336
ignored, and remaining statistics will still be restored. If all
30336-
specified statistics are successfully restored, return
30337+
specified statistics are successfully restored, returns
3033730338
<literal>true</literal>, otherwise <literal>false</literal>.
3033830339
</para>
3033930340
<para>

src/backend/statistics/attribute_stats.c

+95-21
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum attribute_stats_argnum
3838
{
3939
ATTRELATION_ARG = 0,
4040
ATTNAME_ARG,
41+
ATTNUM_ARG,
4142
INHERITED_ARG,
4243
NULL_FRAC_ARG,
4344
AVG_WIDTH_ARG,
@@ -59,6 +60,7 @@ static struct StatsArgInfo attarginfo[] =
5960
{
6061
[ATTRELATION_ARG] = {"relation", REGCLASSOID},
6162
[ATTNAME_ARG] = {"attname", NAMEOID},
63+
[ATTNUM_ARG] = {"attnum", INT2OID},
6264
[INHERITED_ARG] = {"inherited", BOOLOID},
6365
[NULL_FRAC_ARG] = {"null_frac", FLOAT4OID},
6466
[AVG_WIDTH_ARG] = {"avg_width", INT4OID},
@@ -76,6 +78,22 @@ static struct StatsArgInfo attarginfo[] =
7678
[NUM_ATTRIBUTE_STATS_ARGS] = {0}
7779
};
7880

81+
enum clear_attribute_stats_argnum
82+
{
83+
C_ATTRELATION_ARG = 0,
84+
C_ATTNAME_ARG,
85+
C_INHERITED_ARG,
86+
C_NUM_ATTRIBUTE_STATS_ARGS
87+
};
88+
89+
static struct StatsArgInfo cleararginfo[] =
90+
{
91+
[C_ATTRELATION_ARG] = {"relation", REGCLASSOID},
92+
[C_ATTNAME_ARG] = {"attname", NAMEOID},
93+
[C_INHERITED_ARG] = {"inherited", BOOLOID},
94+
[C_NUM_ATTRIBUTE_STATS_ARGS] = {0}
95+
};
96+
7997
static bool attribute_statistics_update(FunctionCallInfo fcinfo);
8098
static Node *get_attr_expr(Relation rel, int attnum);
8199
static void get_attr_stat_type(Oid reloid, AttrNumber attnum,
@@ -116,9 +134,9 @@ static bool
116134
attribute_statistics_update(FunctionCallInfo fcinfo)
117135
{
118136
Oid reloid;
119-
Name attname;
120-
bool inherited;
137+
char *attname;
121138
AttrNumber attnum;
139+
bool inherited;
122140

123141
Relation starel;
124142
HeapTuple statup;
@@ -164,21 +182,51 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
164182
/* lock before looking up attribute */
165183
stats_lock_check_privileges(reloid);
166184

167-
stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG);
168-
attname = PG_GETARG_NAME(ATTNAME_ARG);
169-
attnum = get_attnum(reloid, NameStr(*attname));
185+
/* user can specify either attname or attnum, but not both */
186+
if (!PG_ARGISNULL(ATTNAME_ARG))
187+
{
188+
Name attnamename;
189+
190+
if (!PG_ARGISNULL(ATTNUM_ARG))
191+
ereport(ERROR,
192+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
193+
errmsg("cannot specify both attname and attnum")));
194+
attnamename = PG_GETARG_NAME(ATTNAME_ARG);
195+
attname = NameStr(*attnamename);
196+
attnum = get_attnum(reloid, attname);
197+
/* note that this test covers attisdropped cases too: */
198+
if (attnum == InvalidAttrNumber)
199+
ereport(ERROR,
200+
(errcode(ERRCODE_UNDEFINED_COLUMN),
201+
errmsg("column \"%s\" of relation \"%s\" does not exist",
202+
attname, get_rel_name(reloid))));
203+
}
204+
else if (!PG_ARGISNULL(ATTNUM_ARG))
205+
{
206+
attnum = PG_GETARG_INT16(ATTNUM_ARG);
207+
attname = get_attname(reloid, attnum, true);
208+
/* annoyingly, get_attname doesn't check attisdropped */
209+
if (attname == NULL ||
210+
!SearchSysCacheExistsAttName(reloid, attname))
211+
ereport(ERROR,
212+
(errcode(ERRCODE_UNDEFINED_COLUMN),
213+
errmsg("column %d of relation \"%s\" does not exist",
214+
attnum, get_rel_name(reloid))));
215+
}
216+
else
217+
{
218+
ereport(ERROR,
219+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
220+
errmsg("must specify either attname or attnum")));
221+
attname = NULL; /* keep compiler quiet */
222+
attnum = 0;
223+
}
170224

171225
if (attnum < 0)
172226
ereport(ERROR,
173227
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
174228
errmsg("cannot modify statistics on system column \"%s\"",
175-
NameStr(*attname))));
176-
177-
if (attnum == InvalidAttrNumber)
178-
ereport(ERROR,
179-
(errcode(ERRCODE_UNDEFINED_COLUMN),
180-
errmsg("column \"%s\" of relation \"%s\" does not exist",
181-
NameStr(*attname), get_rel_name(reloid))));
229+
attname)));
182230

183231
stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG);
184232
inherited = PG_GETARG_BOOL(INHERITED_ARG);
@@ -241,7 +289,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
241289
&elemtypid, &elem_eq_opr))
242290
{
243291
ereport(WARNING,
244-
(errmsg("unable to determine element type of attribute \"%s\"", NameStr(*attname)),
292+
(errmsg("unable to determine element type of attribute \"%s\"", attname),
245293
errdetail("Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST.")));
246294
elemtypid = InvalidOid;
247295
elem_eq_opr = InvalidOid;
@@ -257,7 +305,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
257305
{
258306
ereport(WARNING,
259307
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
260-
errmsg("could not determine less-than operator for attribute \"%s\"", NameStr(*attname)),
308+
errmsg("could not determine less-than operator for attribute \"%s\"", attname),
261309
errdetail("Cannot set STATISTIC_KIND_HISTOGRAM or STATISTIC_KIND_CORRELATION.")));
262310

263311
do_histogram = false;
@@ -271,7 +319,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
271319
{
272320
ereport(WARNING,
273321
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
274-
errmsg("attribute \"%s\" is not a range type", NameStr(*attname)),
322+
errmsg("attribute \"%s\" is not a range type", attname),
275323
errdetail("Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM.")));
276324

277325
do_bounds_histogram = false;
@@ -857,8 +905,8 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
857905
AttrNumber attnum;
858906
bool inherited;
859907

860-
stats_check_required_arg(fcinfo, attarginfo, ATTRELATION_ARG);
861-
reloid = PG_GETARG_OID(ATTRELATION_ARG);
908+
stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELATION_ARG);
909+
reloid = PG_GETARG_OID(C_ATTRELATION_ARG);
862910

863911
if (RecoveryInProgress())
864912
ereport(ERROR,
@@ -868,8 +916,8 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
868916

869917
stats_lock_check_privileges(reloid);
870918

871-
stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG);
872-
attname = PG_GETARG_NAME(ATTNAME_ARG);
919+
stats_check_required_arg(fcinfo, cleararginfo, C_ATTNAME_ARG);
920+
attname = PG_GETARG_NAME(C_ATTNAME_ARG);
873921
attnum = get_attnum(reloid, NameStr(*attname));
874922

875923
if (attnum < 0)
@@ -884,13 +932,39 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
884932
errmsg("column \"%s\" of relation \"%s\" does not exist",
885933
NameStr(*attname), get_rel_name(reloid))));
886934

887-
stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG);
888-
inherited = PG_GETARG_BOOL(INHERITED_ARG);
935+
stats_check_required_arg(fcinfo, cleararginfo, C_INHERITED_ARG);
936+
inherited = PG_GETARG_BOOL(C_INHERITED_ARG);
889937

890938
delete_pg_statistic(reloid, attnum, inherited);
891939
PG_RETURN_VOID();
892940
}
893941

942+
/*
943+
* Import statistics for a given relation attribute.
944+
*
945+
* Inserts or replaces a row in pg_statistic for the given relation and
946+
* attribute name or number. It takes input parameters that correspond to
947+
* columns in the view pg_stats.
948+
*
949+
* Parameters are given in a pseudo named-attribute style: they must be
950+
* pairs of parameter names (as text) and values (of appropriate types).
951+
* We do that, rather than using regular named-parameter notation, so
952+
* that we can add or change parameters without fear of breaking
953+
* carelessly-written calls.
954+
*
955+
* Parameters null_frac, avg_width, and n_distinct all correspond to NOT NULL
956+
* columns in pg_statistic. The remaining parameters all belong to a specific
957+
* stakind. Some stakinds require multiple parameters, which must be specified
958+
* together (or neither specified).
959+
*
960+
* Parameters are only superficially validated. Omitting a parameter or
961+
* passing NULL leaves the statistic unchanged.
962+
*
963+
* Parameters corresponding to ANYARRAY columns are instead passed in as text
964+
* values, which is a valid input string for an array of the type or element
965+
* type of the attribute. Any error generated by the array_in() function will
966+
* in turn fail the function.
967+
*/
894968
Datum
895969
pg_restore_attribute_stats(PG_FUNCTION_ARGS)
896970
{

0 commit comments

Comments
 (0)