@@ -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+
7997static bool attribute_statistics_update (FunctionCallInfo fcinfo );
8098static Node * get_attr_expr (Relation rel , int attnum );
8199static void get_attr_stat_type (Oid reloid , AttrNumber attnum ,
@@ -116,9 +134,9 @@ static bool
116134attribute_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+ */
894968Datum
895969pg_restore_attribute_stats (PG_FUNCTION_ARGS )
896970{
0 commit comments