aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-02-26 16:36:11 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2025-02-26 16:36:20 -0500
commit40e27d04b4f643cfb78af8db42a1f2e700ec9876 (patch)
tree80c8df6b40ca3eaec64fcebfff9eb4c3cd2fd824 /src/backend
parentf734c9fc3a91959c2473a1e33fd9b60116902175 (diff)
downloadpostgresql-40e27d04b4f643cfb78af8db42a1f2e700ec9876.tar.gz
postgresql-40e27d04b4f643cfb78af8db42a1f2e700ec9876.zip
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 5b6d13eec. 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
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/statistics/attribute_stats.c116
1 files changed, 95 insertions, 21 deletions
diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index 66a5676c810..6bcbee0edba 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -38,6 +38,7 @@ enum attribute_stats_argnum
{
ATTRELATION_ARG = 0,
ATTNAME_ARG,
+ ATTNUM_ARG,
INHERITED_ARG,
NULL_FRAC_ARG,
AVG_WIDTH_ARG,
@@ -59,6 +60,7 @@ static struct StatsArgInfo attarginfo[] =
{
[ATTRELATION_ARG] = {"relation", REGCLASSOID},
[ATTNAME_ARG] = {"attname", NAMEOID},
+ [ATTNUM_ARG] = {"attnum", INT2OID},
[INHERITED_ARG] = {"inherited", BOOLOID},
[NULL_FRAC_ARG] = {"null_frac", FLOAT4OID},
[AVG_WIDTH_ARG] = {"avg_width", INT4OID},
@@ -76,6 +78,22 @@ static struct StatsArgInfo attarginfo[] =
[NUM_ATTRIBUTE_STATS_ARGS] = {0}
};
+enum clear_attribute_stats_argnum
+{
+ C_ATTRELATION_ARG = 0,
+ C_ATTNAME_ARG,
+ C_INHERITED_ARG,
+ C_NUM_ATTRIBUTE_STATS_ARGS
+};
+
+static struct StatsArgInfo cleararginfo[] =
+{
+ [C_ATTRELATION_ARG] = {"relation", REGCLASSOID},
+ [C_ATTNAME_ARG] = {"attname", NAMEOID},
+ [C_INHERITED_ARG] = {"inherited", BOOLOID},
+ [C_NUM_ATTRIBUTE_STATS_ARGS] = {0}
+};
+
static bool attribute_statistics_update(FunctionCallInfo fcinfo);
static Node *get_attr_expr(Relation rel, int attnum);
static void get_attr_stat_type(Oid reloid, AttrNumber attnum,
@@ -116,9 +134,9 @@ static bool
attribute_statistics_update(FunctionCallInfo fcinfo)
{
Oid reloid;
- Name attname;
- bool inherited;
+ char *attname;
AttrNumber attnum;
+ bool inherited;
Relation starel;
HeapTuple statup;
@@ -164,21 +182,51 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
/* lock before looking up attribute */
stats_lock_check_privileges(reloid);
- stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG);
- attname = PG_GETARG_NAME(ATTNAME_ARG);
- attnum = get_attnum(reloid, NameStr(*attname));
+ /* user can specify either attname or attnum, but not both */
+ if (!PG_ARGISNULL(ATTNAME_ARG))
+ {
+ Name attnamename;
+
+ if (!PG_ARGISNULL(ATTNUM_ARG))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot specify both attname and attnum")));
+ attnamename = PG_GETARG_NAME(ATTNAME_ARG);
+ attname = NameStr(*attnamename);
+ attnum = get_attnum(reloid, attname);
+ /* note that this test covers attisdropped cases too: */
+ if (attnum == InvalidAttrNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ attname, get_rel_name(reloid))));
+ }
+ else if (!PG_ARGISNULL(ATTNUM_ARG))
+ {
+ attnum = PG_GETARG_INT16(ATTNUM_ARG);
+ attname = get_attname(reloid, attnum, true);
+ /* annoyingly, get_attname doesn't check attisdropped */
+ if (attname == NULL ||
+ !SearchSysCacheExistsAttName(reloid, attname))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column %d of relation \"%s\" does not exist",
+ attnum, get_rel_name(reloid))));
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("must specify either attname or attnum")));
+ attname = NULL; /* keep compiler quiet */
+ attnum = 0;
+ }
if (attnum < 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot modify statistics on system column \"%s\"",
- NameStr(*attname))));
-
- if (attnum == InvalidAttrNumber)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" of relation \"%s\" does not exist",
- NameStr(*attname), get_rel_name(reloid))));
+ attname)));
stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG);
inherited = PG_GETARG_BOOL(INHERITED_ARG);
@@ -241,7 +289,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
&elemtypid, &elem_eq_opr))
{
ereport(WARNING,
- (errmsg("unable to determine element type of attribute \"%s\"", NameStr(*attname)),
+ (errmsg("unable to determine element type of attribute \"%s\"", attname),
errdetail("Cannot set STATISTIC_KIND_MCELEM or STATISTIC_KIND_DECHIST.")));
elemtypid = InvalidOid;
elem_eq_opr = InvalidOid;
@@ -257,7 +305,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
{
ereport(WARNING,
(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\"", attname),
errdetail("Cannot set STATISTIC_KIND_HISTOGRAM or STATISTIC_KIND_CORRELATION.")));
do_histogram = false;
@@ -271,7 +319,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("attribute \"%s\" is not a range type", NameStr(*attname)),
+ errmsg("attribute \"%s\" is not a range type", attname),
errdetail("Cannot set STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM or STATISTIC_KIND_BOUNDS_HISTOGRAM.")));
do_bounds_histogram = false;
@@ -857,8 +905,8 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
AttrNumber attnum;
bool inherited;
- stats_check_required_arg(fcinfo, attarginfo, ATTRELATION_ARG);
- reloid = PG_GETARG_OID(ATTRELATION_ARG);
+ stats_check_required_arg(fcinfo, cleararginfo, C_ATTRELATION_ARG);
+ reloid = PG_GETARG_OID(C_ATTRELATION_ARG);
if (RecoveryInProgress())
ereport(ERROR,
@@ -868,8 +916,8 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
stats_lock_check_privileges(reloid);
- stats_check_required_arg(fcinfo, attarginfo, ATTNAME_ARG);
- attname = PG_GETARG_NAME(ATTNAME_ARG);
+ stats_check_required_arg(fcinfo, cleararginfo, C_ATTNAME_ARG);
+ attname = PG_GETARG_NAME(C_ATTNAME_ARG);
attnum = get_attnum(reloid, NameStr(*attname));
if (attnum < 0)
@@ -884,13 +932,39 @@ pg_clear_attribute_stats(PG_FUNCTION_ARGS)
errmsg("column \"%s\" of relation \"%s\" does not exist",
NameStr(*attname), get_rel_name(reloid))));
- stats_check_required_arg(fcinfo, attarginfo, INHERITED_ARG);
- inherited = PG_GETARG_BOOL(INHERITED_ARG);
+ stats_check_required_arg(fcinfo, cleararginfo, C_INHERITED_ARG);
+ inherited = PG_GETARG_BOOL(C_INHERITED_ARG);
delete_pg_statistic(reloid, attnum, inherited);
PG_RETURN_VOID();
}
+/*
+ * Import statistics for a given relation attribute.
+ *
+ * Inserts or replaces a row in pg_statistic for the given relation and
+ * attribute name or number. It takes input parameters that correspond to
+ * columns in the view pg_stats.
+ *
+ * Parameters are given in a pseudo named-attribute style: they must be
+ * pairs of parameter names (as text) and values (of appropriate types).
+ * We do that, rather than using regular named-parameter notation, so
+ * that we can add or change parameters without fear of breaking
+ * carelessly-written calls.
+ *
+ * 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_restore_attribute_stats(PG_FUNCTION_ARGS)
{